=== OzuPay Payment Gateway for M-Pesa ===
Contributors: fearofbug
Tags: mpesa, woocommerce, payment gateway, kenya, safaricom
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 5.1.15
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Accept M-Pesa STK Push payments in your WooCommerce store. Customers pay via their phone — no card required.

== Description ==

OzuPay accepts M-Pesa payments in WooCommerce. Customers enter their Safaricom number at checkout and receive a payment prompt on their phone.

= What's included in the free edition =

* **STK Push payments** — send a payment prompt directly to the customer's phone via the Daraja API
* **Payment waiting modal** — shows payment status in real time on the confirmation page
* **Retry support** — customers can resend the STK Push prompt up to 2 times if they missed it
* **Manual verification fallback** — if automation fails, customers can submit their M-Pesa transaction code for admin review
* **Paybill fallback matching** — matches an external Paybill payment by account reference
* **Transaction log** — every Daraja API request and callback is logged for easy troubleshooting
* **Sandbox testing panel** — test your Daraja credentials in the sandbox before going live
* **Health check** — instant feedback on missing credentials, SSL issues, and other common misconfigurations
* **Privacy tools integration** — supports WooCommerce personal-data export and erasure
* **HPOS compatible** — works with WooCommerce High-Performance Order Storage
* **Blocks compatible** — works with the WooCommerce Cart/Checkout Block editor

= What OzuPay Pro adds =

* **M-Pesa on Delivery (COD Deposit)** — deposit + balance on delivery gateway
* **C2B Buy Goods (Till) Reconciliation** — match Till payments made outside an STK prompt
* **B2C Automatic Refunds** — process WooCommerce refunds via the Daraja B2C API
* **Analytics Dashboard** — revenue, conversion, and payment path charts
* **Scheduled Email Reports** — daily, weekly, or monthly payment summary emails
* **POS REST API** — REST endpoints for the OzuPay Android cashier application
* **Webhook Enrichment** — add M-Pesa receipt data to WooCommerce webhook payloads

Upgrade at [ozupay.com](https://ozupay.com/#pricing)

= Requirements =

* **WooCommerce is required** — OzuPay is a WooCommerce payment gateway and does not run without it
* A Safaricom Daraja developer account (free at [developer.safaricom.co.ke](https://developer.safaricom.co.ke))
* Store currency must be set to **KES (Kenyan Shilling)**
* A public HTTPS URL for Daraja callbacks (required for production; not needed for sandbox testing)

== Installation ==

1. Upload the `ozupay-payment-gateway` folder to the `/wp-content/plugins/` directory, or install directly through the WordPress plugins screen.
2. Activate the plugin through the **Plugins** screen in WordPress.
3. Go to **OzuPay → Settings** and enter your Daraja credentials.
4. Go to **WooCommerce → Payments** and enable the **M-Pesa** gateway.
5. Configure the gateway title and description under **WooCommerce → Payments → M-Pesa → Manage**.
6. Test with the Sandbox Testing panel before going live.

= Getting your Daraja credentials =

1. Create a free developer account at [developer.safaricom.co.ke](https://developer.safaricom.co.ke)
2. Create an app under **My Apps** and add the **Lipa Na M-Pesa** product
3. Copy the **Consumer Key** and **Consumer Secret** from the Keys tab
4. Copy the **STK Passkey** from the sandbox credentials section
5. Use shortcode **174379** and passkey from the test credentials page for sandbox testing

== Frequently Asked Questions ==

= What is the test phone number for sandbox STK Push? =

Safaricom's official sandbox test phone is **254708374149**. Any STK Push to this number in sandbox mode will succeed. You can change this in the Sandbox Testing panel.

= What are the sandbox credentials? =

Shortcode: 174379
Passkey: bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919

These are public Safaricom test credentials. The plugin's Sandbox Testing panel can pre-fill these automatically.

= Why is the gateway not showing at checkout? =

The most common reasons:
1. The store currency is not set to KES — go to WooCommerce → Settings → General
2. The gateway is not enabled — go to WooCommerce → Payments and enable M-Pesa
3. Consumer Key, Consumer Secret, Shortcode, or Passkey is missing — go to OzuPay → Settings
4. The Health Check panel (OzuPay → Settings → Health Check) will tell you exactly what is missing

= Why is "Invalid TransactionType" returned by Daraja? =

Your Shortcode Type setting does not match the type registered in Daraja. Paybill numbers use **CustomerPayBillOnline** and Till numbers use **CustomerBuyGoodsOnline**. The sandbox shortcode 174379 is a Paybill — set the type to Paybill.

= Do callbacks work on localhost, and is HTTPS required? =

Daraja requires a publicly accessible HTTPS callback URL. For local testing, use a secure tunnel such as [ngrok](https://ngrok.com), then confirm delivery with the Sandbox Testing panel.

= Can I upgrade to Pro later without losing data? =

Yes. The free and Pro editions use the same database tables and option names (`ozupay_mpesa_settings`, `wp_ozupay_mpesa_transactions`). Upgrading to Pro or switching back to free never deletes your data.

= Where are API credentials stored? =

Consumer Key, Consumer Secret, and STK Passkey are stored AES-256-GCM encrypted in the WordPress options table. The encryption key is derived from your site's `AUTH_KEY` and `SECURE_AUTH_KEY` constants. They are never stored in plain text.

= Does this plugin phone home or send usage data? =

Payment processing uses Daraja. Optional OzuPay diagnostics are **off by default** and run only after you opt in. The report includes your hostname and is not anonymous. Details follow.

== External services ==

This plugin relies on the following external services. Nothing else is contacted.

**1. Safaricom Daraja API (required)**

The plugin connects to Daraja to send STK Push prompts and receive payment results. This core service is required.

Endpoints: `https://api.safaricom.co.ke` (production) and `https://sandbox.safaricom.co.ke` (sandbox, used only when you select Sandbox mode in settings).

What is sent, and when:

* When a customer places an order with the M-Pesa gateway: the customer's Safaricom phone number, the order amount, your store's Paybill/Till shortcode, the order number as the payment reference, and your site's callback URL.
* When the plugin needs an API token (before each request batch): your Daraja Consumer Key and Consumer Secret.
* While a customer is on the payment-waiting page and their payment hasn't confirmed after 15 seconds: your store's Paybill/Till shortcode and the CheckoutRequestID for that specific payment, to proactively check whether Daraja already has an outcome (rate-limited to once every 30 seconds per order).
* Safaricom sends results back to your site's callback URL; nothing is sent by the plugin in that direction.

You supply your own Daraja credentials, so your store's relationship is directly with Safaricom.

Safaricom Daraja API terms and conditions: https://developer.safaricom.co.ke/terms
Safaricom data privacy statement: https://www.safaricom.co.ke/dataprivacystatement/

**2. OzuPay diagnostics (optional, disabled by default)**

If you enable "Share optional diagnostic telemetry" in OzuPay → Settings → Advanced, the plugin sends a daily report to `https://ozupay.com/wp-json/ozls/v1/telemetry`. It also sends once immediately after opt-in. Fresh installs default to off.

What is sent, and when: once per day (and once immediately after you enable it) — your site's hostname, the plugin/PHP/WordPress/WooCommerce version numbers, store locale and country, whether the site is a WordPress multisite install, whether the site is in sandbox or production mode, whether HPOS and block checkout are in use, whether your M-Pesa shortcode is a Paybill or Till, boolean configuration-health flags (for example "credentials configured: yes/no", "callback URL reachable: yes/no"), install and last-active dates, daily aggregate payment counts (initiated, confirmed, failed, retried), and error type slugs with their frequency.

What is never sent: customer names, phone numbers, emails, addresses, order IDs, order contents, payment amounts, M-Pesa receipt numbers, or your Daraja API credentials.

OzuPay terms of service: https://ozupay.com/terms
OzuPay privacy policy: https://ozupay.com/privacy

== Changelog ==

= 5.1.15 =
* fix: Reopening the payment status modal from the "Got it, thank you!" sticky bar's View button (after a manual M-Pesa code had already been submitted) no longer auto-closes and reloads the page a couple of seconds later.

= 5.1.14 =
* security: Removed unused Pro-only deposit/refund setter methods (set_deposit_data, confirm_deposit, mark_balance_collected, set_refund_data, confirm_refund) that had no caller anywhere in Free — a fully-implemented, callable, state-changing method with no caller is still shipping the feature, even if nothing reaches it at runtime.

= 5.1.13 =
* security: A legacy M-Pesa on Delivery order left over from a Pro-to-Free downgrade could have Free automatically run Pro's deposit/balance confirmation logic on a real incoming payment — including setting an order status Free doesn't even register. Free now records the payment (nothing is ever lost) and flags it for manual review instead of pretending to run business logic it doesn't have.

For the full version history, see changelog.txt in the plugin package.
