# etechflow/module-next-day-eligibility

> Automatically manages a Next Day Eligible attribute on products based on real-time stock and a per-product Drop-Ship override, and restricts configured next-day shipping methods at checkout when any cart item is not eligible.

`composer require etechflow/module-next-day-eligibility`

Canonical URL: https://packagento.com/etechflow/module-next-day-eligibility

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: v1.8.4 — released 2026-06-16
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/etechflow/module-next-day-eligibility and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require etechflow/module-next-day-eligibility:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Automatically manages a Next Day Eligible attribute on products based on real-time stock and a per-product Drop-Ship override, and restricts configured next-day shipping methods at checkout when any cart item is not eligible.

## README

**Comprehensive stock-aware shipping restrictions in one module.**

Two independent rules, one admin section, one license:

1. **Next-day eligibility** (auto-managed) — removes configured next-day shipping methods from checkout when any cart item is out of stock or otherwise ineligible. Eligibility is auto-maintained by a stock observer; nothing for the merchant to flip per product.
2. **Backorder express restriction** (opt-in, v1.1.0+) — removes any express methods you list when the cart contains backorder items (out of stock with backorders enabled, or partially short). Useful for merchants who explicitly flag pre-order / made-to-order products and don't want them sold with express delivery.

Both rules raise a single dismissible checkout banner with merchant-customisable wording. Both respect the Drop-Ship Eligible exemption.

Stock-aware. Drop-ship aware. Hyvä compatible. Works with Magento Open Source and Adobe Commerce.

---

### What's new

The version-by-version history lives in `CHANGELOG.md`. Highlights of the most recent releases:

- **v1.4.0** — New per-product `Force Standard Shipping Only` flag. Tick it on the product edit page (under *eTechFlow Shipping*) to hard-disable next-day shipping for that product regardless of stock state. For bulky / hazmat / fragile / made-to-order items. Ships with a CLI verification command: `bin/magento etechflow:nde:verify --sku=<sku>` runs an end-to-end check that the observer + evaluator pipeline is wired correctly.
- **v1.3.0** — Module status banner at the top of admin config (shows whether the module is actually active), PDP badge visibility toggle, drop-ship grid filter, inline tooltips on every field.
- **v1.2.0** — Shipping method fields are now multi-select dropdowns auto-populated from your active shipping methods — merchants no longer need to know technical codes.
- **v1.1.0** — Absorbed the deprecated `ETechFlow_BackorderShippingRestrictor` module's features as an opt-in "Backorder Express Restriction" toggle. The bundle is now 2 modules (NDE + BackorderEtaDisplay).

---

### What it solves

Merchants who advertise next-day delivery hit the same problem from two directions:

| Scenario | Without the module | With the module |
|---|---|---|
| Customer picks "Next Day" on an out-of-stock item | Order ships a week late, refund + 1-star review | Next-day automatically hidden at checkout; banner explains why |
| Customer picks "Express" on a pre-order / backorder item | Same problem — supplier ETA is two weeks, customer paid £15 for next-day | Express methods automatically hidden when the toggle is enabled |
| Drop-shipped products with zero local stock | Marked out of stock, no Add to Cart button | Stay eligible — supplier ships direct, backorders auto-enabled |
| Customer asks "where is my order?" | Volume support tickets | Banner sets the expectation at checkout |

### Requirements

| | |
|---|---|
| **Magento** | Open Source 2.4.4+ OR Adobe Commerce 2.4.4+ |
| **PHP** | 8.1, 8.2, 8.3, or 8.4 |
| **Compatible themes** | Luma (default) + Hyvä |

### Installation

#### Option A — Composer (recommended)

```bash
composer require etechflow/module-next-day-eligibility:^1.1
bin/magento module:enable ETechFlow_NextDayEligibility
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

#### Option B — Manual (from zip)

1. Unzip `etechflow-module-next-day-eligibility-1.1.0.zip` into:
   ```
   <magento-root>/app/code/ETechFlow/NextDayEligibility/
   ```
   **The directory MUST be named `ETechFlow` (capital E, capital T, capital F) — case-sensitive on Linux servers.**

2. Enable and set up:
   ```bash
   bin/magento module:enable ETechFlow_NextDayEligibility
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

3. Verify:
   ```bash
   bin/magento module:status | grep NextDayEligibility
   ```

### After install — quick setup

Open the admin and go to **Stores → Configuration → eTechFlow → Next Day Eligibility**.

#### Step 1 — License

**License → License Key**: paste the key from your purchase email and save.

> **Don't have a key yet?** Dev/staging hosts are free. Any URL matching `localhost`, `*.test`, `*.local`, `staging.*`, `dev.*`, `*.magento.cloud`, ngrok tunnels, or RFC 1918 IPs runs at full features without a key. For non-standard dev domains, set **License → Production Environment = No** instead.

#### Step 2 — Enable the module

**General Settings → Enable Module = Yes** → save.

#### Step 3 — Pick your next-day shipping methods

**General Settings → Next Day Shipping Methods** is a multi-select dropdown. The list is auto-populated from your store's currently active shipping methods (the same list shown under Stores → Configuration → Sales → Shipping Methods). Tick the methods you want removed for ineligible carts — typically just your paid next-day or express options. Hold <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> to select multiple. Save.

> **⚠️ Important — keep at least one fallback method unticked.** Don't tick every option. The intended pattern is to tick only your paid express / next-day methods so a standard or free option always stays available for ineligible carts. If you accidentally select everything, a safety net returns the original rates and logs a warning to `var/log/system.log` to prevent a stuck checkout — but that's a guardrail, not a config strategy. See `docs/USER_GUIDE.md` "Configuration trap" for the typical UK setups.

That's the core feature done. Browse to a product detail page — you'll see the green "Next Day Eligible" / grey "Standard Delivery Only" badge under the price.

#### Step 4 — (optional) Enable Backorder Express Restriction

If you also want to block express shipping on backorder items:

_(README truncated for .md surface. Full README on https://packagento.com/etechflow/module-next-day-eligibility.)_

## Changelog

All notable changes to this module. Adheres to [Semantic Versioning](https://semver.org/).

---

### [1.8.0] — 2026-06-03 — Stripe portal licensing + admin gate page

Adds Stripe Checkout subscription flow gated by the eTechFlow licensing
portal. Customers can now subscribe directly from inside Magento Admin
without leaving the panel — plan selection, card entry, and SP-XXXX key
activation happen in the same embedded frame. HMAC + bundle key
validation is retained as a fallback so existing v1.7.x licences
continue to work without re-activation.

#### Added

- **Admin subscription gate** under *Stores → Configuration → ETECHFLOW →
  Next Day Eligibility* — when no licence is detected on a production
  environment, the configuration page is replaced with three plan cards
  (Starter $19/mo, Professional $49/mo, Enterprise $99/mo) and an
  embedded customer-details form.
- **`Controller/Adminhtml/License/Checkout.php`** — builds a Stripe
  Checkout session against the selected plan and redirects the browser
  to Stripe's hosted payment page.
- **`Controller/Adminhtml/License/Activated.php`** — Stripe success-URL
  endpoint. Calls the portal's `/license/activate` route with the
  session ID, receives an SP-XXXX licence in the response, and writes
  it to `core_config_data`.
- **`Controller/Adminhtml/License/Gate.php`** — admin route that renders
  the gate page (redirects to config when licensed).
- **`Block/Adminhtml/License/{Gate,Activated}.php`** — view-model helpers
  for the gate and activated templates.
- **`view/adminhtml/templates/license/{gate,activated}.phtml`** — dark
  navy gate page with 3 plan cards + Stripe checkout form, and the
  License Activated success page with the SP-XXXX key + Copy button.
- **`etc/adminhtml/routes.xml`** — new admin route
  `etechflow_nextdayeligibility`.
- **`etc/adminhtml/menu.xml`** — *Stores → Settings → Next Day
  Eligibility* menu item that opens the gate page.
- **`etc/adminhtml/di.xml`** — registers the missing
  `EligibilityPanel` UI form modifier (was shipped without DI wiring
  in v1.7.0 - v1.7.1, so the "Why eligible?" panel never rendered).
- **License section expansion** in `etc/adminhtml/system.xml` — adds
  `portal_url` and `portal_api_url` fields.
- **Payment (Stripe) section** in `etc/adminhtml/system.xml` —
  `stripe_secret_key` (obscure + Encrypted backend model),
  `stripe_publishable_key`, `stripe_currency`.
- **Tri-state portal validation** in `Model/LicenseValidator.php` — the
  validator's portal call returns `?bool`: `true` (valid), `false`
  (explicit reject, HTTP 200+valid:false / 401 / 403), or `null`
  (unreachable). Only `null` falls back to the 48h local grace, so
  admin IP-removal or subscription suspension locks the storefront
  within 60 seconds rather than waiting for the grace window.
- **Split cache TTLs** — `CACHE_TTL_VALID = 60` and
  `CACHE_TTL_REJECT = 60` so re-authorisation propagates within 1 minute
  in both directions.

#### Changed

- `Model/LicenseValidator.php` constructor goes from 2 arguments to 4
  (`ScopeConfigInterface`, `StoreManagerInterface`, `CacheInterface`,
  `Curl`). Callers using `ObjectManager::get()` are unaffected. Direct
  instantiation in tests or DI overrides needs updating.
- `Model/BackorderManager.php::syncBackordersWithDropShip()` now also
  sets `is_in_stock = true` on the stock item when Drop-Ship Eligible
  is turned on. Without this, Magento's auto-OOS flip (qty=0 +
  backorders=No at save time) left drop-ship products silently
  unsalable despite backorders=Allow being set later by the observer.
- Removed the hyphen-suffix dev-host bypass (e.g. `*-dev.com`,
  `*-staging.com`). It false-matched legitimate production hosts like
  `magento-dev.etechflow.com` and gave them a free unlimited bypass.
- Added `.ngrok-free.dev` to the recognised tunnel suffixes.

#### Test changes

_(Changelog truncated for .md surface. Full history on https://packagento.com/etechflow/module-next-day-eligibility.)_

## Recent Versions

| Version | Released |
|---|---|
| v1.8.4 | 2026-06-16 |
| v1.8.3 | 2026-06-13 |
| v1.8.2 | 2026-06-10 |
| v1.8.1 | 2026-06-05 |
| 1.8.0 | 2026-06-03 |
| 1.7.1 | 2026-05-25 |
| 1.7.0 | 2026-05-24 |
| 1.6.5 | 2026-05-24 |
| 1.6.4 | 2026-05-23 |
| 1.6.2 | 2026-05-23 |

Showing 10 of 11 versions. Full release history on https://packagento.com/etechflow/module-next-day-eligibility.

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | ^103.0\|\|^104.0 |
| magento/module-bundle | ^101.0\|\|^102.0 |
| magento/module-catalog | ^104.0\|\|^105.0 |
| magento/module-catalog-inventory | ^100.4\|\|^101.0 |
| magento/module-checkout | ^100.4\|\|^101.0 |
| magento/module-config | ^101.2\|\|^102.0 |
| magento/module-configurable-product | ^100.4\|\|^101.0 |
| magento/module-eav | ^102.1\|\|^103.0 |
| magento/module-grouped-product | ^100.4\|\|^101.0 |
| magento/module-quote | ^101.2\|\|^102.0 |
| magento/module-store | ^101.1\|\|^102.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0 |

### Suggest

| Package | Constraint |
|---|---|
| etechflow/module-backorder-eta-display | Pair with Backorder ETA Display to show next-day eligibility and backorder ETAs together. |
| hyva-themes/magento2-default-theme | Hyvä Theme support is built in — install Hyvä to enable Tailwind-styled templates automatically. |

## Quality

Latest release (v1.8.4) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | not tested |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 167 | 13 errors, 154 warnings (ruleset: Magento2) — 34 auto-fixable with phpcbf |
| PHPMD | Warning | 41 | 41 rule violations (NPathComplexity:10, CyclomaticComplexity:7, TooManyPublicMethods:7, MissingImport:5, UnusedFormalParameter:3) |
| Cpd | Warning | 2 | 2 duplicated chunks spanning 73 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Pass | 0 |  |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 58 | 58 | – | – |
| 2.4.8 | – | 58 | 58 | – |
| 2.4.9 | – | – | 58 | N/A |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["etechflow/module-next-day-eligibility"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

etechflow is a Magento 2 vendor on Packagento. See https://packagento.com/etechflow.md for their full catalogue.

