orangecat/module-quickorder

Bulk add-to-cart by SKU for Magento 2 B2B — search, paste, or upload a CSV to fill the cart in one shot

Maintainers

Package info

github.com/olivertar/m2_quickorder

Language:HTML

Type:magento2-module

pkg:composer/orangecat/module-quickorder

Statistics

Installs: 20

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

0.0.2 2026-06-07 18:28 UTC

This package is auto-updated.

Last update: 2026-06-07 18:54:50 UTC


README

Bulk add-to-cart by SKU — search, paste, or upload a CSV to fill the cart in one shot.

Module: Orangecat_QuickOrder Version: 1.0.0 License: OSL-3.0 Author: Oliverio Gombert olivertar@gmail.com

Table of Contents

  1. Overview
  2. Theme Compatibility
  3. Requirements
  4. Installation
  5. What Gets Installed
  6. Configuration
  7. Store Admin Guide
  8. Buyer Guide (Frontend)
  9. Developer Guide
  10. REST API
  11. Frontend Routes Reference
  12. DevOps & Integrator Notes

Overview

Orangecat_QuickOrder gives logged-in customers a dedicated page to build and submit large orders without browsing the catalog. Three input methods are available in parallel on the same page:

  • Live search — type at least 3 characters to search by SKU or product name; results appear in a dropdown with price and type badge.
  • Bulk SKU textarea — paste a comma- or newline-separated list of SKUs; the module resolves each SKU to a product and adds it to the staging list.
  • CSV upload — upload a file with SKU,Qty rows; header row is auto-detected and skipped.

All resolved products land in an editable staging table where the buyer can adjust quantities, select configurable options, and remove individual rows before sending everything to the cart in one request.

Position in the Orangecat B2B Dependency Chain

Orangecat_Core (via composer: orangecat/core)
  └── Orangecat_Company
        └── ...

Orangecat_QuickOrder    ← this module (standalone, no inter-module dependency)

Orangecat_QuickOrder is independent — it does not depend on Orangecat_Company or any other Orangecat module. It integrates with core Magento catalog, checkout, and customer modules only.

Theme Compatibility

Theme Status Notes
Luma Supported quickorder.phtml + RequireJS AMD widget quick-order.js. LESS styles in web/css/source/_module.less.
Hyvä Supported quickorder_hyva.phtml with inline Alpine.js initQuickOrder() component. CSS utilities in web/css/hyva/module.css. Layout handle hyva_quickorder_index_index.xml swaps the template and loads the Hyvä CSS.
Breeze Evolution Supported Uses the same Luma template (quickorder.phtml). The JS widget is registered in breeze_default.xml as a Breeze bundle item. LESS styles in web/css/breeze/_default.less.

Each theme uses its own layout handle. The Hyvä template is at view/frontend/templates/quickorder_hyva.phtml — not in a view/hyva/ subdirectory, following this project's convention.

Requirements

Dependency Version / Notes
Magento 2 2.4.x
PHP >= 8.1
magento/module-customer Bundled with Magento
magento/module-catalog Bundled with Magento
magento/module-checkout Bundled with Magento
magento/module-configurable-product Bundled with Magento (required for configurable option resolution)
magento/module-config Bundled with Magento
magento/module-store Bundled with Magento

No dependency on orangecat/core or any other Orangecat module.

Installation

Via Git Submodule (recommended for this project)

# From repo root
git submodule add git@github.com:olivertar/m2_quickorder.git app/code/Orangecat/QuickOrder
git submodule update --init --recursive

Enable the Module

Run inside the PHP container (reward shell):

bin/magento module:enable Orangecat_QuickOrder
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

What Gets Installed

  • No database tables — this module creates no schema changes.
  • No EAV attributes — no customer or product attributes are added.
  • No data patches — no default records, CMS pages, or roles are created.

setup:upgrade only registers the module version in setup_module. All module state lives in core_config_data (the enabled/disabled flag).

Configuration

Path: Stores > Configuration > Orangecat > Quick Order

General

Label Config path Default Description
Enable Quick Order orangecat_quickorder/general/enabled Yes Master switch. When disabled, the frontend page returns 404 and all AJAX endpoints return empty/error responses. The account navigation link is also hidden (via ifconfig).
orangecat_quickorder/general/enabled

Scope: Default / Website / Store View.

Store Admin Guide

Enabling / Disabling

  1. Go to Stores > Configuration > Orangecat > Quick Order.
  2. Set Enable Quick Order to Yes or No.
  3. Save and flush cache.

No other admin configuration or UI exists. The module has no admin grids, order management screens, or report panels — it is a pure frontend feature.

Verifying the Link Appears

After enabling, logged-in customers should see a Quick Order link in the My Account sidebar. If the link is missing, confirm orangecat_quickorder/general/enabled is 1 for the active store view and that static content has been deployed.

Buyer Guide (Frontend)

Accessing Quick Order

Direct URL: https://your-store.test/quickorder

The Quick Order link appears in the My Account sidebar navigation for all logged-in customers. Guests are redirected to the login page. When the module is disabled, the page returns a 404.

Step 1 — Add Products to Your List

Three methods are available on the same page:

Search by SKU or Name

  1. Type at least 3 characters in the Search Products input.
  2. A dropdown appears with matching results showing product name, SKU, price, and type.
  3. Click a result to add it to the staging list.

For configurable products, the row will show option selectors (e.g. Color, Size) that must be completed before adding to cart.

Bulk SKU Input

  1. Paste SKUs into the Bulk SKU Input textarea, separated by commas or new lines.
  2. Click Add to List.
  3. Each valid SKU resolves to a product row. Invalid or not-found SKUs are reported as errors below the action area.

Only simple products are supported via bulk input. Configurable, bundle, and grouped products are skipped with an explanatory message.

CSV Upload

  1. Prepare a CSV file:
SKU,Qty
PROD-001,5
PROD-002,2
SIMPLE-ABC,10

A header row (SKU,Qty) is optional — if the first cell is literally sku (case-insensitive) it is skipped.

  1. Click Choose File, select the CSV, then click Upload CSV.
  2. Valid rows appear in the staging list; invalid SKUs are reported as errors.

Same restriction as bulk input: only simple products are accepted from CSV.

Step 2 — Review and Adjust

The Your Selection table shows all staged products:

Column Editable Notes
Product No Product name
SKU No Product SKU
Options Yes Dropdowns for configurable attributes; N/A for simple
Price No Formatted product price
Qty Yes Numeric input, minimum 1
Actions × button removes the row

Use Clear All to empty the entire list.

Step 3 — Add All to Cart

Click Add all to Cart. The module validates that all configurable options are selected before submitting. On success:

  • All items are added to the active cart in one request.
  • The mini-cart refreshes automatically.
  • The staging list clears.

On partial failure (e.g. out-of-stock item), the server returns an error message and no items are added.

Developer Guide

Module Structure

Orangecat/QuickOrder/
├── Controller/
│   ├── Index/
│   │   └── Index.php              — GET /quickorder (page; login + enabled check)
│   └── Ajax/
│       ├── Search.php             — POST /quickorder/ajax/search
│       ├── BulkSku.php            — POST /quickorder/ajax/bulksku
│       ├── Upload.php             — POST /quickorder/ajax/upload
│       └── AddToCart.php          — POST /quickorder/ajax/addtocart
├── Helper/
│   └── Data.php                   — isEnabled() helper (legacy; use Model/Config)
├── Model/
│   └── Config.php                 — isEnabled() via ScopeConfigInterface
├── etc/
│   ├── module.xml                 — sequence: Customer, Catalog, Checkout
│   ├── acl.xml                    — Orangecat_QuickOrder::config
│   ├── config.xml                 — default enabled = 1
│   ├── frontend/routes.xml        — frontName: quickorder
│   └── adminhtml/system.xml       — Enable Quick Order field
├── registration.php
└── view/frontend/
    ├── layout/
    │   ├── quickorder_index_index.xml      — Luma page (2columns-left)
    │   ├── hyva_quickorder_index_index.xml — Hyvä: swaps template + loads CSS
    │   ├── customer_account.xml            — sidebar nav link (all themes)
    │   └── breeze_default.xml              — Breeze JS bundle registration
    ├── templates/
    │   ├── quickorder.phtml        — Luma/Breeze template (data-mage-init)
    │   └── quickorder_hyva.phtml   — Hyvä template (Alpine.js initQuickOrder())
    └── web/
        ├── js/quick-order.js       — Luma/Breeze RequireJS AMD widget
        ├── css/source/_module.less — Luma LESS styles
        ├── css/breeze/_default.less — Breeze LESS styles
        └── css/hyva/module.css     — Hyvä CSS utilities (z-index, animation, etc.)

Key Classes

Orangecat\QuickOrder\Model\Config

Primary config reader. Inject via constructor.

isEnabled(): bool   // reads orangecat_quickorder/general/enabled, store scope

Orangecat\QuickOrder\Helper\Data

Extends AbstractHelper. Provides the same isEnabled() check. Kept for compatibility; prefer Model\Config in new code.

Controllers

All AJAX controllers implement HttpPostActionInterface and return JsonFactory responses.

Class Method Route Key behavior
Controller\Index\Index execute() GET /quickorder Redirects to 404 if disabled; redirects to login if not logged in
Controller\Ajax\Search execute() POST /quickorder/ajax/search query param (min 3 chars); searches SKU and name; returns max 10 results with configurable options array
Controller\Ajax\BulkSku execute() POST /quickorder/ajax/bulksku skus param; splits on comma/newline; resolves via ProductRepositoryInterface; simple products only
Controller\Ajax\Upload execute() POST /quickorder/ajax/upload csv_file multipart; parsed with Magento\Framework\File\Csv; auto-detects header row; simple products only
Controller\Ajax\AddToCart execute() POST /quickorder/ajax/addtocart items JSON param; adds each item via Magento\Checkout\Model\Cart; supports super_attribute for configurables

Search Response Shape

{
  "items": [
    {
      "id": 42,
      "name": "Blue Widget",
      "sku": "BW-001",
      "price": "$19.99",
      "type": "simple",
      "options": []
    },
    {
      "id": 55,
      "name": "T-Shirt",
      "sku": "TS-XL",
      "price": "$29.00",
      "type": "configurable",
      "options": [
        {
          "id": "93",
          "label": "Color",
          "code": "color",
          "values": [
            { "value": "56", "label": "Blue" },
            { "value": "57", "label": "Red" }
          ]
        }
      ]
    }
  ]
}

AddToCart Request Shape

POST /quickorder/ajax/addtocart
Content-Type: application/x-www-form-urlencoded

items=%5B%7B%22id%22%3A42%2C%22qty%22%3A3%2C%22super_attribute%22%3A%7B%7D%7D%5D&form_key=abc123

Decoded items value:

[
  { "id": 42, "qty": 3, "super_attribute": {} },
  { "id": 55, "qty": 1, "super_attribute": { "93": "56" } }
]

Observers

This module registers no observers.

Plugins

This module registers no plugins.

JS Components

Frontend — Luma / Breeze

File Type Description
web/js/quick-order.js RequireJS AMD widget Manages all UI state: search debounce (300 ms), result rendering, staging list, qty/option change handlers, CSV upload, bulk SKU, add-to-cart with mini-cart invalidation via Magento_Customer/js/customer-data

Initialized via data-mage-init in quickorder.phtml:

{
  "Orangecat_QuickOrder/js/quick-order": {
    "searchUrl": "...",
    "uploadUrl": "...",
    "bulkSkuUrl": "...",
    "addToCartUrl": "...",
    "formKey": "..."
  }
}

Frontend — Hyvä

File Type Description
quickorder_hyva.phtml Inline Alpine.js initQuickOrder() function returns Alpine data object with handleSearch, handleBulkSku, handleUpload, handleAddToCart, selectProduct, removeItem, clearList. Uses hyva.getFormKey() and window.dispatchMessages for notifications. Cart refresh via CustomEvent('reload-customer-section-data').

Email Templates

This module sends no transactional emails.

ACL Resources

Resource ID Title Location
Orangecat_QuickOrder::config Orangecat Quick Order Configuration Stores > Settings > Configuration

Adding Custom Logic

  • Disable for specific customer groups: add a plugin on Controller\Index\Index::execute() or Model\Config::isEnabled() that checks the customer session's group ID.
  • Extend search results: add a plugin on Controller\Ajax\Search::execute() to filter or enrich the $items array before the JSON response is built.
  • Post-add-to-cart hook: observe checkout_cart_product_add_after to trigger custom logic (logging, price override) after each product is added by the Quick Order flow.

REST API

This module exposes no REST API endpoints. There is no etc/webapi.xml.

Frontend Routes Reference

Route Controller Access
GET /quickorder Controller\Index\Index Logged-in customers; 404 if disabled
POST /quickorder/ajax/search Controller\Ajax\Search Any (enabled check only)
POST /quickorder/ajax/bulksku Controller\Ajax\BulkSku Any (enabled check only)
POST /quickorder/ajax/upload Controller\Ajax\Upload Any (enabled check only)
POST /quickorder/ajax/addtocart Controller\Ajax\AddToCart Any (enabled check only)

The AJAX endpoints do not enforce an active customer session — they rely on the form key for CSRF protection and check the enabled flag. Add a customer-session guard in a plugin if stricter access control is required.

DevOps & Integrator Notes

Deployment Checklist

bin/magento module:enable Orangecat_QuickOrder
bin/magento setup:upgrade          # registers module version only (no schema changes)
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

Integration Token Scope

No REST API. No integration token permissions required for this module.

Disabling Without Uninstalling

bin/magento module:disable Orangecat_QuickOrder
bin/magento setup:upgrade
bin/magento cache:flush

No dependent Orangecat modules — safe to disable at any time without cascade effects.

Data Integrity

  • No database tables are created or modified by this module.
  • The only persisted state is core_config_data rows for orangecat_quickorder/*.
  • Disabling the module leaves those rows in place; re-enabling restores prior settings.
  • No cart data is stored by this module — items written to the cart follow standard Magento quote lifecycle.