# etechflow/module-in-store-pickup

> Click & Collect / in-store pickup for Magento 2. Multi-store admin (stores, holidays, tags, amenities, pickup windows). Hyvä Checkout Magewire-native. Auto-fills shipping address from picked store (kills the wrong-tax bug). Standalone — works without any other ETechFlow module — and integrates richer when paired with NDE / DD / BED.

`composer require etechflow/module-in-store-pickup`

Canonical URL: https://packagento.com/etechflow/module-in-store-pickup

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: 2.2.0 — released 2026-06-06
- **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-in-store-pickup 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-in-store-pickup:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Click & Collect / in-store pickup for Magento 2. Multi-store admin (stores, holidays, tags, amenities, pickup windows). Hyvä Checkout Magewire-native. Auto-fills shipping address from picked store (kills the wrong-tax bug). Standalone — works without any other ETechFlow module — and integrates richer when paired with NDE / DD / BED.

## README

**Click & Collect for Magento 2.** Multi-store admin (stores, holidays, tags, amenities, pickup windows). Hyvä Checkout Magewire-native. **Auto-fills shipping address from the picked store** — the killer feature every other C&C module misses.

> *Status: v1.0.0 Phase 1 (foundation only — admin CRUD ships in Phase 2-4).*

### Why this exists

Every existing Magento 2 C&C module shares the same structural bug: when a customer picks "in-store collection", they're still required to fill in a shipping address. They type their home address, Magento charges tax based on it, the merchant has to manually fix every order. We searched the market and 8+ vendors all have this same problem.

ETechFlow_InStorePickup solves it: when the customer picks a store, the shipping address auto-fills with the store's address. Tax calculation works. Order export works. Refund routing works. No manual cleanup.

### Features

| | |
|---|---|
| Multi-store admin (stores, hours, holidays, tags, amenities, pickup windows) | Phase 2-4 |
| Auto-fill shipping address from picked store | Phase 6 |
| Hyvä Checkout Magewire-native store picker | Phase 7 |
| Hyvä Theme + Luma fallback templates | Phase 7 |
| Per-installation HMAC license + bundle key | ✅ Phase 1 |
| Verify CLI (`etechflow:isp:verify`) | ✅ Phase 1 |
| Tideways profiler instrumentation (`ETechFlow_ISP_*` spans) | ✅ Phase 1 |
| Pickup-ready email + 6-digit verification code | Phase 8 |
| Optional NDE / DD / BED integrations | Phase 9 |
| Holiday import CLI (`etechflow:isp:import-holidays`) | Phase 10 |

### Standalone — and better when paired

This module works fully standalone. It does NOT require any other eTechFlow module.

When the sibling modules ARE installed, soft-detection kicks in:

| Optional pairing | Standalone | With pairing |
|---|---|---|
| **+ NDE** | Reads MSI stock | Uses NDE's eligibility engine (drop-ship + supplier rules) |
| **+ DD** | Own pickup windows | Optional: reuse DD's time intervals (consolidated UX) |
| **+ BED** | Generic "available once restocked" | Per-product backorder ETA shown on pickup options |

### Compatibility

| Platform | Status |
|---|---|
| Magento Open Source 2.4.4 – 2.4.8 | ✓ |
| Adobe Commerce 2.4.4 – 2.4.8 | ✓ |
| Hyvä Theme + Hyvä Checkout | ✓ Magewire-native |
| PHP 8.1 / 8.2 / 8.3 / 8.4 | ✓ |

### Installation

```bash
composer require etechflow/module-in-store-pickup:^1.0
bin/magento module:enable ETechFlow_InStorePickup
bin/magento setup:upgrade
bin/magento setup:di:compile      # production mode only
bin/magento cache:flush
```

`setup:upgrade` creates 11 tables prefixed `etechflow_isp_`.

### Smoke test

```bash
bin/magento etechflow:isp:verify
```

Phase 1 verify confirms license + config + all 11 tables exist.

### License

Proprietary — see `LICENSE.txt`. Commercial licenses available at <https://etechflow.com>.

## Changelog

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

---

### [2.1.1] — 2026-06-03 — Billing-period plans (weekly / monthly / yearly)

#### Changed

- **License gate now offers billing periods instead of feature tiers.** Replaced the Starter/Professional/Enterprise cards with **Weekly $9 / Monthly $29 / Yearly $290** (one full-feature price point, USD; yearly ≈ 2 months free). Updated `Controller/Adminhtml/License/Checkout.php` `PLAN_INFO` (`isp_weekly|monthly|yearly`) and the gate template. Matches the eTechFlow portal's new billing-period subscription model.

### [2.1.0] — 2026-06-03 — Portal licensing, Stripe in-admin checkout, pickup-aware order email + checkout-capture fixes

#### Added

- **SP-XXXX portal licensing** — `Model/LicenseValidator.php` (hybrid HMAC per-module / shared-bundle key + portal-validated subscription with two-factor domain + server-IP binding, IP-block auto-management, dev-host bypass, result caching). All admin pages (Stores / Holidays / Tags / Amenities / Pickup Windows) gate to a locked page until licensed.
- **In-admin Stripe checkout + gate page** — `Controller/Adminhtml/License/{Gate,Checkout,Activated}.php` with a dark-navy 3-plan gate (Starter / Professional / Enterprise) that takes payment via Stripe and auto-saves the issued license key. New `payment` config group (Stripe keys, encrypted) and `license` fields (issued_key, portal_url, bundle key).
- **Pickup-aware order confirmation email** — `view/frontend/email/order_new_pickup.html` + `Block/Email/PickupInfo.php` + `templates/email/pickup-info.phtml`. For Click & Collect orders it replaces the shipping/tracking wording with collection wording and shows a Collection Details panel (store, address, date & time) near the top; non-pickup orders are unchanged.

#### Fixed

- **Pickup details never reached the order.** The picker saved store + slot to the quote, but the module had no `etc/fieldset.xml`, so nothing copied them to `sales_order`. Added the `sales_convert_quote` → `to_order` fieldset for `etechflow_isp_pickup_store_id` / `etechflow_isp_pickup_at`. This restores the admin pickup card, the pickup-aware confirmation email, and the staff/ready emails for real orders.
- **`etc/adminhtml/system.xml` was invalid** — a `<comment>` contained a raw `<code>GB</code>` tag without CDATA, which failed XSD validation and blocked `setup:upgrade` / `di:compile`. Wrapped in CDATA.
- **"Add New Store" form crashed** — `view/adminhtml/ui_component/etechflow_isp_store_form.xml` used 5 `<hint>` elements inside fieldset `<settings>`, which the UI-component schema rejects. Removed (descriptive text only; no fields lost).

### [2.0.1] — 2026-05-26 — Fix integration-test carrier assertion + v2.0.0 always-a-patch follow-up

Pure test + patch hygiene. No customer-facing changes, no schema changes,
no behaviour changes.

#### Fixed

- **Integration-test carrier section reported a false failure on v2.0.0.**
  `etechflow:isp:integration-test` was asserting the v1.x architecture
  (one shipping method per active store, named `etechflow_isp_<store_code>`).
  v2.0.0 changed the carrier to return a single unified `pickup` method,
  with the actual store choice happening separately inside the modal flow.
  The carrier code was correct; only the test assertion was stale.
  Updated to assert the new behaviour: exactly one method returned, code
  matches `Carrier\InStorePickup::METHOD_CODE` (`pickup`), at least one
  active store exists as a precondition. Result: `integration-test` now
  passes 40/40 instead of 39/40.

#### Added

- **`Setup/Patch/Data/V201ReleaseMarker.php`** — continues the
  always-a-patch discipline. Same template as `V200ReleaseMarker`; depends
  on it so patches run in version order.

#### Migration

```bash
composer require etechflow/module-in-store-pickup:^2.0.1
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

_(Changelog truncated for .md surface. Full history on https://packagento.com/etechflow/module-in-store-pickup.)_

## Recent Versions

| Version | Released |
|---|---|
| 2.2.0 | 2026-06-06 |
| 2.1.2 | 2026-06-04 |
| 2.0.2 | 2026-06-04 |
| 1.3.2 | 2026-06-04 |
| 2.1.1 | 2026-06-03 |
| 2.1.0 | 2026-06-03 |
| 2.0.1 | 2026-05-26 |
| 2.0.0 | 2026-05-26 |
| 1.3.1 | 2026-05-22 |
| 1.3.0 | 2026-05-22 |

Showing 10 of 28 versions. Full release history on https://packagento.com/etechflow/module-in-store-pickup.

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | ^103.0\|\|^104.0 |
| magento/module-backend | ^102.0\|\|^103.0 |
| magento/module-catalog-inventory | ^100.4\|\|^101.0 |
| magento/module-config | ^101.2\|\|^102.0 |
| magento/module-customer | ^103.0\|\|^104.0 |
| magento/module-eav | ^102.1\|\|^103.0 |
| magento/module-quote | ^101.2\|\|^102.0 |
| magento/module-sales | ^103.0\|\|^104.0 |
| magento/module-shipping | ^100.4\|\|^101.0 |
| magento/module-store | ^101.1\|\|^102.0 |
| magento/module-ui | ^101.2\|\|^102.0 |
| magewirephp/magewire | ^1.0\|\|^2.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0 |

### Suggest

| Package | Constraint |
|---|---|
| etechflow/module-backorder-eta-display | Optional. When installed, the pickup-ready date for backorder items pulls from BED's per-product ETA. |
| etechflow/module-delivery-date | Optional. When installed, ISP can reuse DD's time intervals as pickup-window slots — consolidated admin UX. |
| etechflow/module-next-day-eligibility | Optional. When installed, ISP uses NDE's stock-eligibility rules engine for richer per-product picklability checks (drop-ship, supplier mode, force-standard overrides). |
| hyva-themes/magento2-hyva-checkout | Hyvä Checkout activates the Magewire-native store picker. Plain Hyvä Theme / Luma use Alpine + server-rendered fallback. |

## Quality

Latest release (2.2.0) 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 | 143 | 3 errors, 140 warnings (ruleset: Magento2) — 15 auto-fixable with phpcbf |
| PHPMD | Warning | 56 | 56 rule violations (MissingImport:19, UnusedFormalParameter:12, NPathComplexity:11, CyclomaticComplexity:10, ExcessiveMethodLength:2) |
| Cpd | Pass | 0 |  |
| Composer validate | Info | 1 | valid; 1 advisory note (composer validate --strict) |

#### 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 | 89 | 89 | – | – |
| 2.4.8 | – | 89 | 89 | – |
| 2.4.9 | – | – | 89 | 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-in-store-pickup"],
  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.

