MMISDocs

MMIS Documentation

Installation steps and a complete reference for every field and function in the admin, with concrete examples โ€” the same level of detail our support uses to help customers.

Installation

Requirements

Magento 2.4.x โ€” tested on 2.4.9, compatible with previous 2.4.* releases. PHP 8.1โ€“8.5. Compatible with both the default Luma theme and the Hyvรค theme.

Setup steps

  1. 1. Add the credentials you'll receive by email to auth.json in your Magento project root:
    { "http-basic": { "repo.codingrow.com": { "username": "...", "password": "..." } } }
  2. 2. composer config repositories.codingrow composer https://repo.codingrow.com
  3. 3. composer require codingrow/module-mmis
  4. 4. bin/magento module:enable Codingrow_Mmis
  5. 5. bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush
  6. 6. Paste your license key into Admin โ†’ Stores โ†’ Configuration โ†’ Codingrow Extensions โ†’ MMIS โ†’ License โ†’ License Key, save, then bin/magento cache:flush.

The whole admin interface โ€” every label, tooltip and guide โ€” is available in 7 languages, auto-selected per admin user:

๐Ÿ‡ฌ๐Ÿ‡ง English ๐Ÿ‡ฎ๐Ÿ‡น Italiano ๐Ÿ‡ช๐Ÿ‡ธ Espaรฑol ๐Ÿ‡ซ๐Ÿ‡ท Franรงais ๐Ÿ‡ฉ๐Ÿ‡ช Deutsch ๐Ÿ‡ง๐Ÿ‡ท Portuguรชs ๐Ÿ‡ณ๐Ÿ‡ฑ Nederlands

Uninstallation

composer remove codingrow/module-mmis then bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush. Products already imported are never touched automatically โ€” use the rollback tool first if you also want them removed.

User guide

Import Profiles

Every supplier/feed you import from is its own Profile: own feed URL, own mapping, own schedule, own settings โ€” completely independent from every other profile. You can run as many profiles as you have suppliers, side by side, on the same catalog, and each one only ever touches the products it created itself (never a product created manually by an operator, even if it happened to share the same SKU prefix).

Feed source & format

A profile reads its feed from one of three sources:

SourceWhat you configure
URL (default)A direct HTTP/HTTPS link. Supports .zip-compressed feeds transparently (detected by file signature, not by extension).
Magento file systemA path inside your Magento installation (e.g. var/import/feed.csv) โ€” useful if the supplier drops files via SFTP into a folder you control.
FTP serverHost + username + password (stored encrypted) โ€” the module connects and downloads the file itself.

Three feed formats are supported: CSV (with configurable delimiter: comma, semicolon or tab), XML (you specify which repeating element represents one product) and JSON (array of objects).

Column mapping

Six fields are always required (Product name, Price, Quantity/Stock, Weight, EAN, Brand) โ€” each gets its own row with a source column, a default value, and a transformation. Beyond those six, you can add as many free mapping rows as you like, targeting any real Magento attribute (not just a fixed list of historical fields) โ€” including custom attributes you've created yourself.

Example โ€” a supplier feed has a column called prezzo_base for price and peso_kg for weight: map "Price" โ†’ source column prezzo_base, "Weight" โ†’ source column peso_kg. Column names never matter, only which column you point each row at.

Transformations & text functions

Every mapping row has a "Transform" type:

TransformWhat it does
NoneDirect copy from the source column's value.
Static valueIgnores the source column, always uses the fixed text you type in "Value".
Text templateFree text with {ColumnName} placeholders โ€” see functions below.
Search and replaceCase-insensitive search in the source column's value, replaced with your text (case-sensitive as typed).
Math formulaA self-contained expression โ€” see Math formulas below.

Inside a Text template, besides the plain {ColumnName} placeholder, seven functions are available (text fields only):

FunctionEffectExample
ucase{Column}ALL UPPERCASEucase{Brand} โ†’ "ACME"
lcase{Column}all lowercaselcase{Brand} โ†’ "acme"
proper{Column}Capitalizes Each Wordproper{name} โ†’ "red bar" โ†’ "Red Bar"
trim{Column}Removes leading/trailing spacesโ€”
left{Column,N}First N charactersleft{SKU,5}
val{Column}Normalizes a European-format number ("1.234,56") into standard format ("1234.56"), no decimal roundingโ€”
replace{Column,'search','new'}Search/replace only within that value (case-insensitive search), usable inside a larger templatereplace{name,'Ref.','Reference'}
Combined example โ€” template {ucase{Brand}} - {proper{name}} on a row where Brand="acme" and name="red bar" produces "ACME - Red Bar". A misspelled function name is left visible unchanged in the output instead of silently disappearing, so a typo is always noticeable.

Math formulas

For numeric fields only (Price, Weight, Quantity, or any numeric custom attribute): a self-contained expression using {ColumnName} placeholders, the four basic operators (+ - * /) and parentheses โ€” nothing else (no functions, no comparisons). The result is always rounded to a maximum of 2 decimals.

Example โ€” "Price" with formula {B2B price} * 1.30 applies a 30% markup on top of the supplier's wholesale price. ({price} + {shipping_cost}) / 1.22 adds shipping then removes 22% VAT to get a net price.

Multi-field text replacement

A search-and-replace rule that can target several raw feed columns at once, run before mapping even starts. Cleaning a column at the source propagates to every mapping row that reads it โ€” instead of repeating the same fix on each derived field separately.

Example โ€” columns "Product_title, HTML_description" (two fields), search "SUPPLIERCODE ", replace with nothing โ†’ strips a supplier prefix from both raw columns in one shot, so "Product name" and "Description", if mapped from those columns, already arrive clean.

Import filters (Groups/Rules)

Every feed row passes through three filters, always in this order โ€” a later filter only ever sees rows that survived the one before it:

  1. Allowed feed categories โ€” always first. A category not on the allowed list discards the row here, before any Group is even considered.
  2. Groups/Rules โ€” optional. If no Group is configured, every row from step 1 passes through untouched. If at least one Group exists, only rows captured by a Group pass โ€” rows captured by no Group are discarded (different from "no filter at all").
  3. Group's target category โ€” if set inside the Group that captured the row, it replaces the category path entirely; if left empty, the feed's own category path is used as-is.
Example โ€” allowed categories = "Home & Garden, Sporting Goods"; a Group "Chairs only" with rule "name contains chair" and target category "Furniture/Chairs". A row "Office chair" in feed category "Home & Garden > Chairs" passes step 1, is captured at step 2, and lands under "Default Category/Furniture/Chairs" โ€” not under "Home & Garden/Chairs" as the feed alone would suggest.
Note: as soon as one Group exists, items captured by no Rule are discarded entirely. To still import "everything else", add a second, lower- priority Group with a rule that generically matches the remaining rows.

Categories

The category tree is created automatically from each product's feed category path โ€” no need to pre-create categories in Magento. A "Parent category" setting lets you nest an entire profile's categories under one shared root, useful when several profiles share the same catalog and you want to keep their category trees visually separate. Categories that end up empty (e.g. after a supplier discontinues a whole product line) can be cleaned up with one click or from the CLI.

Image gallery

Map any number of feed columns to image roles (base / small / thumbnail / gallery) โ€” a single column can serve multiple roles at once. Downloaded images are optionally compressed (resized if wider than 1200px, recompressed at JPEG quality 85, kept only if the result is actually lighter) with a configurable concurrency and a disk-space watchdog that pauses downloads โ€” never product data โ€” if free space runs low.

Configurable products (variants)

Feed rows sharing the same value in a "Group/parent column" become variants of one configurable product. Any number of attributes can vary simultaneously โ€” size, color, and a third attribute together, for example โ€” each just needs its own mapping row with a column that gives a different value per variant.

Real example โ€” a "90ยฐ elbow" product line varying by angle (90ยฐ/45ยฐ), pipe size (10/20/30/40) and material (copper/ composite): map all three feed columns to their Magento attributes, select all three in "Variant attributes", and the parent product shows three independent dropdowns on its page โ€” verified end-to-end with 16 simultaneous variant combinations.
Note: the variant attribute must already exist in Magento as a proper Dropdown attribute, scoped "Per Website" (not Global โ€” a global attribute can never vary between variants, a native Magento requirement), and assigned to the product's attribute set. Bundle products are not supported.

Grouped products

Conceptually different from configurable: no variant attribute, no group column โ€” just a direct link between a "container" parent and any number of simple products that stay completely independent (their own price, stock, and navigable page each), useful when a supplier sells both the individual components separately and a kit that shows them together with a quantity selector for each.

Example โ€” "Drill Kit" made of 3 items also sold individually: on the child rows (drill, battery, charger), map "Grouped: parent SKU" to a column holding "KIT-DRILL"; on the row representing the kit itself, map "Grouped: child SKUs" (purely descriptive) to mark it as the container. Result: a "Drill Kit" page listing all three components with their own quantity selectors, and each component still has its own individual product page.

Stock management

Stock updates can be absolute (replace the value) or relative (add/subtract from the current quantity) โ€” useful for suppliers whose feed reports deltas instead of totals. Backorders and "manage stock" follow your profile's configuration, not a single global setting.

Preview & output file

Two ways to see what a sync would actually write to the catalog โ€” only the mapped fields, never the category/sellability/Group filters (the sample is partial on purpose):

PreviewReflects the form's current values, even unsaved โ€” click it while editing to see the effect immediately, without touching the profile.
Download output fileUses the last saved configuration and produces a downloadable JSON file.

Scheduling & notifications

Each profile has its own cron schedule (from every 15 minutes to once a day, or a custom cron expression) for both the full catalog sync and a lighter stock/price-only sync. Email notifications (success/warning/critical error) are configured per profile, so different suppliers can have different alerting policies on the same store.

Product lifecycle: nothing is deleted by surprise

A product that disappears from the feed, or gets excluded by a filter, is always disabled first โ€” never deleted โ€” and re-enables itself automatically if it reappears in a later sync. Permanent deletion is a separate, optional setting (off by default): only a product left disabled for longer than a configurable number of days gets actually deleted, and only then.

CLI commands

Every action is also available from the command line (useful for cron, or for very large first imports run over SSH): run a profile's sync, export/import a profile's configuration, roll back everything a profile has ever imported, clean up orphaned categories, and more โ€” each with a dry-run preview by default where destructive.