Skip to content

MelisCommerce ​

Full e-commerce framework for MelisPlatform — catalog, customers, cart/checkout/orders, coupons, shipping and SEO. Package melisplatform/melis-commerce.

Purpose ​

MelisCommerce adds a complete commerce layer to a Melis site: a catalog (products, variants, attributes, categories, prices, stock), a B2B customer model (accounts + contacts), the cart/checkout/order pipeline, coupons, currencies, shipping, returns, documents and SEO. It ships a back-office management suite and a front-office shop built entirely from droppable templating plugins. The data layer uses 59 melis_ecom_* tables, 26 services, 10 rich entities and 33 listeners; data access uses Eloquent (bundled illuminate/database), wrapped by Melis-style event-driven services.

Enable it ​

Add to config/melis.module.load.php:

php
return [
    'MelisCommerce',
];

Requires melisplatform/melis-core ^5.2. Database tables are provisioned automatically by MelisDbDeploy (deltas under install/dbdeploy/). The module is offered by the Melis installer as an optional component.

Object model ​

ConceptWhat it is
ProductA container for variants — not itself a sellable unit.
VariantThe sellable unit: has its own SKU, stock and price. A product with no real options still has one main variant.
AttributeA filterable/variant-defining property (e.g. Color, Size) with typed, translatable values. Products declare which attributes they use; each variant picks one value per attribute.
PriceResolved for a (countryId, groupId) pair with VAT; falls back gracefully (see Pricing resolution).
AccountA B2B organisation (melis_ecom_client); has a company record, group and addresses.
Contact / PersonAn individual (melis_ecom_client_person) who logs in; can belong to multiple accounts.
BasketAnonymous (keyed by clientKey) or persistent (tied to an account); merges on login.
OrderCreated at status -1 (temporary) during checkout; moves to 1 (New order) after payment.

Key services ​

All services extend MelisComGeneralService and are registered in config/module.config.php. Every public method is wrapped in meliscommerce_service_*_start / *_end events (see Events & listeners).

Service aliasRole
MelisComProductServicegetProductById, getProductList → MelisProduct entity
MelisComVariantServicegetVariantById, getVariantListByProductId, getVariantBySKU, getMainVariantByProductId → MelisVariant
MelisComCategoryServicegetCategoryById, getCategoryListById(Recursive) → MelisCategory
MelisComAttributeServicegetAttributeById, getAttributes → MelisAttribute
MelisComPriceServicegetItemPrice($itemId, $countryId, $groupId, $type) — price with fallback hierarchy
MelisComProductSearchServiceFront-office product search
MelisComSeoServiceCommerce SEO (URLs / meta for products and categories)
MelisComClientServicegetClientById, getClientList, getClientByIdAndClientPerson → MelisClient
MelisComContactServiceContact (person) management
MelisComClientGroupsServiceClient groups (used for group-specific pricing)
MelisComAuthenticationServiceFront-office login: login, getClientId, getPersonId, getClientGroup, setClientId, logout, hasIdentity
MelisComBasketServicegetBasket, getPersistentBasket, getAnonymousBasket, addVariantToBasket, transferAnonymousBasketToPersistentBasket → MelisBasket
MelisComOrderServicegetOrderById, getOrderList → MelisOrder
MelisComOrderCheckoutServiceTwo-phase checkout: checkoutStep1_prePayment, checkoutStep2_postPayment
MelisComPostPaymentServicePost-payment transaction recording
MelisComOrderProductReturnServiceProduct returns / RMA
MelisComCouponServicegetCouponById, getCouponList → MelisCoupon
MelisComCurrencyServiceCurrencies
MelisComShipmentCostServiceShipping cost computation
MelisComStockEmailAlertServiceLow-stock email alerts (VARIANTSLOWSTOCK)
MelisComDocumentServicegetDocumentById, getDocumentsByRelation → MelisDocument
MelisComDuplicationServiceDuplicate products / variants
MelisComLinksServiceFront-office commerce link builder
MelisComCacheServiceCommerce cache (commerce_big_services; key prefixes product-/category-/variant-/document-/attribute-)
MelisComHeadSEO head helper (updateTitleAndDescription)
MelisComGeneralServiceBase class; helpers: getTableColumns, getEcomLang, getFrontPluginLangId

Pricing & stock resolution ​

MelisComPriceService::getItemPrice($itemId, $countryId, $groupId, $type) walks a fallback chain:

  1. specific country + specific group
  2. specific country + general group
  3. general country (price_country_id = 0) + specific group
  4. general country + general group
  5. (for a variant) fall back to the product price

Stock is per variant per country (melis_ecom_variant_stock). When an order drops stock below the threshold, the VARIANTSLOWSTOCK email is sent to the configured recipients.

Checkout pipeline ​

Two phases in MelisComOrderCheckoutService:

Phase 1 — checkoutStep1_prePayment($clientId) Validates basket and addresses, computes all costs and shipping, generates the order reference, then calls MelisComOrderService::saveOrder(). The order is saved with ord_status = -1 (temporary). Fires meliscommerce_service_checkout_step1_prepayment_start/_end and …_save_success (carries the new orderId).

Phase 2 — checkoutStep2_postPayment() Called after the payment gateway returns. MelisComPostPaymentService::processPostPayment() records the transaction in melis_ecom_order_payment and moves the order off status -1 to a real status (e.g. 1 = New order). Fires meliscommerce_service_checkout_step2_postpayment_start/_end.

Order statuses: -1 temporary · 1 New order · 2 On hold · 3 Shipped · 4 Delivered · 5 Cancelled · 6 Payment error.

Events & listeners ​

Every service method emits meliscommerce_service_*_start and *_end events. The named arguments (built by makeArrayFromParameters via reflection) and the results key travel with the event.

  • _start listener: mutate inputs before the work runs.
  • _end listener: mutate $params['results'] before the caller sees it.

This is the primary extension mechanism — no subclassing needed. The built-in coupon discount is itself a listener on meliscommerce_service_get_item_price_end.

The 33 bundled listeners fall into four families:

FamilyExamples
Save / validate…SaveProductListener, …SaveOrderListener, …SaveClientListener, …ValidateVariantListener
Cascade cleanup (country/language removed)…ProductPriceCountryDeletedListener, …CategoryCountryLink…, …SEOLanguageDeletedListener
Checkout / pricing / stock…CheckoutCouponListener, …CouponProductPriceListener, …ShipmentCostListener, …PostPaymentListener, …VariantCheckLowStockListener
Front-office SEO routing…SEOReformatToRoutePageUrlListener, …SEODispatchRouterCommerceUrlListener, …SEOMetaPageListener

Backoffice ​

The full commerce back office lives under the MelisCommerce left-menu section.

Menu entryControllerManages
CatalogsMelisComCategory(List)Catalog / category drag-and-drop tree; translations, per-country availability, SEO
ProductsMelisComProduct(List)Products → variants, prices, texts, SEO, images
AccountsMelisComClient(List)B2B accounts (company, group, addresses, contacts, orders, files)
ContactsMelisComContactPeople; CSV import/export; linkable to multiple accounts
OrdersMelisComOrder(List) + MelisComOrderCheckoutOrders + 7-step BO creation tunnel; statuses; returns
CouponsMelisComCoupon(List)Discount coupons (% or amount; per account / product)
AttributesMelisComAttribute(List)Attributes + typed, translatable values
Countries / Commerce languages / Currencies / Order status / Client's groupsMelisComCountry / MelisComLanguage / MelisComCurrency / MelisComOrderStatus / MelisComClientsGroupReference data (list + edit modal)
Commerce settingsMelisComSettingsGlobal stock-alert threshold; account-name strategy (sa_type)

Dashboard widgets: OrdersNumber, OrderMessages, SalesRevenue.

Front office ​

Templating plugins are registered under config/plugins/{products,categories,clients,orders}/ and as controller_plugins in module.config.php. Drop them into a CMS page drag-drop zone.

AreaPlugins
CatalogProductShowPlugin, ProductListPlugin, ProductSearchPlugin, CategoryTreePlugin, CategoryProductListPlugin, RelatedProductsPlugin, AttributesShowPlugin, ProductAttributePlugin, ProductPriceRangePlugin
Cart & checkoutAddToCartPlugin, CartPlugin, CheckoutPlugin, CheckoutCartPlugin, CheckoutAddressesPlugin, CheckoutCouponPlugin, CheckoutSummaryPlugin, CheckoutConfirmSummaryPlugin, CheckoutConfirmPlugin
AccountLoginPlugin, RegisterPlugin, AccountPlugin, ProfilePlugin, BillingAddressPlugin, DeliveryAddressPlugin, LostPasswordGetEmailPlugin, LostPasswordResetPlugin
Orders (customer)OrderPlugin, OrderHistoryPlugin, OrderMessagesPlugin, OrderShippingDetailsPlugin, OrderReturnProductPlugin, OrderAddressPlugin

Database tables ​

59 tables with the melis_ecom_* prefix, grouped by subsystem:

GroupKey tables
Products & variantsmelis_ecom_product, melis_ecom_product_text + _text_type, melis_ecom_product_attribute, melis_ecom_product_category, melis_ecom_variant, melis_ecom_variant_attribute_value, melis_ecom_variant_stock, melis_ecom_assoc_variant + _type
Attributesmelis_ecom_attribute + _trans, melis_ecom_attribute_type, melis_ecom_attribute_value + _value_trans
Categories & geomelis_ecom_category + _trans, melis_ecom_country_category, melis_ecom_country, melis_ecom_lang
Pricing & currencymelis_ecom_price, melis_ecom_currency
Clients (B2B)melis_ecom_client, melis_ecom_client_person + _person_emails, melis_ecom_client_company, melis_ecom_client_account_rel, melis_ecom_client_person_rel, melis_ecom_client_address + _address_type, melis_ecom_client_groups, melis_ecom_civility, melis_ecom_settings_account
Baskets & ordersmelis_ecom_basket_anonymous, melis_ecom_basket_persistent, melis_ecom_order, melis_ecom_order_basket, melis_ecom_order_address, melis_ecom_order_payment + _type, melis_ecom_order_shipping, melis_ecom_order_message, melis_ecom_order_status + _trans, melis_ecom_order_product_return + _details
Couponsmelis_ecom_coupon + _coupon_client / _coupon_order / _coupon_product
Documents & SEOmelis_ecom_document + _doc_type + _doc_relations, melis_ecom_seo, melis_ecom_stock_email_alert

Examples ​

Read a product, its main variant and a resolved price

php
$prdSrv   = $sm->get('MelisComProductService');
$varSrv   = $sm->get('MelisComVariantService');
$priceSrv = $sm->get('MelisComPriceService');

// getProductById($productId, $langId = null, $countryId = null, $groupId = -1, $docType = null, $docSubType = [])
$product = $prdSrv->getProductById($prdId, $langId, $countryId);  // → MelisProduct
$texts   = $product->getTexts();       // typed texts (TITLE, …) per language
$cats    = $product->getCategories();  // categories the product belongs to

// getMainVariantByProductId($productId, $langId = null, $countryId = null, $groupId = 1)
$variant = $varSrv->getMainVariantByProductId($prdId, $langId, $countryId);  // → MelisVariant

// getItemPrice($itemId, $countryId, $groupId, $type = 'variant', array $data = [])
$price = $priceSrv->getItemPrice($variant->getId(), $countryId, $groupId, 'variant');
// $price['price'] (net), $price['price_currency'], $price['price_details']

Add to basket and run the two-phase checkout

php
$basketSrv   = $sm->get('MelisComBasketService');
$checkoutSrv = $sm->get('MelisComOrderCheckoutService');

// addVariantToBasket($variantId, $quantity, $clientId, $clientKey = null)
$basketSrv->addVariantToBasket($variantId, 1, $clientId);

// Merge an anonymous cart after login
$basketSrv->transferAnonymousBasketToPersistentBasket($clientKey, $clientId);

// Phase 1 — creates order at status -1 (temporary)
$step1 = $checkoutSrv->checkoutStep1_prePayment($clientId);
// $step1['orderId'] — hand to payment gateway

// Phase 2 — after gateway returns; records payment, moves order off -1
$step2 = $checkoutSrv->checkoutStep2_postPayment();

Authenticate a front-office customer

php
$auth = $sm->get('MelisComAuthenticationService');
$res  = $auth->login($email, $password, $rememberMe);  // login($email, $password, $rememberMe = false)
if ($res['success']) {
    $personId = $auth->getPersonId();   // logged-in contact (cper_id)
    $clientId = $auth->getClientId();   // currently-selected account (cli_id)
    $group    = $auth->getClientGroup(); // pricing group → feeds getItemPrice()
}

Hook the shop without subclassing

php
// Attach a listener to any meliscommerce_service_*_start or *_end event.
// _start → mutate inputs; _end → mutate $params['results'].
$this->attachEventListener(
    $events, '*', 'meliscommerce_service_get_item_price_end',
    function ($e) {
        $params = $e->getParams();
        $price  = $params['results'];
        // modify $price, then:
        $params['results'] = $price;
        return $params;
    }
);

Key files ​

ConcernPath
Module config (services, controllers, plugins)vendor/melisplatform/melis-commerce/config/module.config.php
Back-office interface configvendor/melisplatform/melis-commerce/config/interface/
Front-office plugin configvendor/melisplatform/melis-commerce/config/plugins/
Email templates configvendor/melisplatform/melis-commerce/config/app.emails.php
Servicesvendor/melisplatform/melis-commerce/src/Service/
Entities (10)vendor/melisplatform/melis-commerce/src/Entity/
Table gateways (59)vendor/melisplatform/melis-commerce/src/Model/Tables/
Controllers (BO + FO plugins)vendor/melisplatform/melis-commerce/src/Controller/
Listeners (33)vendor/melisplatform/melis-commerce/src/Listener/
DB deltasvendor/melisplatform/melis-commerce/install/dbdeploy/

See also: Module reference · melis-core · melis-cms · melis-dbdeploy.