Orangecat_Company

June 2, 2026 · View on GitHub

Module: Orangecat_Company 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. Frontend User Guide
  9. Developer Guide
  10. REST API
  11. Frontend Routes Reference
  12. DevOps & Integrator Notes

Overview

Orangecat_Company is the core B2B module of the Orangecat suite. It introduces the concept of a Company entity into Magento 2 — a legal business unit that groups multiple customers under a shared identity with role-based access control.

The module handles:

  • Company entity management (create, approve, suspend, reject)
  • Company registration form on the frontend (separate from standard customer registration)
  • Customer approval workflow — accounts can require admin approval before login is allowed
  • Role assignment per company user (Admin, Manager, Buyer)
  • Frontend user management panel for Company Admins
  • Access controls for standard registration and login flows
  • Email notifications for registration events and status changes
  • Full REST API and Admin UI for company management

Position in the Orangecat B2B Dependency Chain

Orangecat_Core (via composer: orangecat/core)
  └── Orangecat_Company                     ← this module
        ├── Orangecat_Prices
        │     ├── Orangecat_PricesList
        │     └── Orangecat_PricesCompany
        ├── Orangecat_CompanyCredit
        ├── Orangecat_CompanyMethods
        ├── Orangecat_CompanySalesRep
        └── Orangecat_PurchaseOrder

All other B2B modules depend on this one. It must be installed and enabled first.


Theme Compatibility

ThemeStatusNotes
LumaSupported"Create a Company" link placed in header.links. Standard .phtml templates.
Breeze EvolutionSupportedCustom template breeze/company-register-link.phtml. Link placed in top.links.
HyväSupportedAlpine.js-compatible templates. Link placed in header.customer.logged.out.links. Custom CSS loaded from web/css/hyva/module.css.

Each theme has its own layout handles and templates. No cross-theme interference.


Requirements

  • Magento 2.4.x
  • PHP > 8.1
  • orangecat/core (composer dependency)
  • Modules: Magento_Customer, Magento_Eav, Magento_Backend, Magento_Ui, Magento_Theme

Installation

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

Enable the Module

Run inside the PHP container (reward shell):

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

What Gets Installed

Database Tables

TableDescription
mycompanyCompany flat table — name, legal name, email, tax ID, address, status, website
mycompany_roleCompany roles with JSON permissions
mycompany_customerLink table joining companies, customers, and roles. Also stores per-user purchase limits.

mycompany columns: entity_id, name, name_legal, email, tax_id, address, city, country, region, postalcode, telephone, status, website_id, created_at, updated_at

mycompany_customer columns: link_id, company_id, customer_id, role_id, max_purchase_amount, max_period_amount

A customer can belong to only one company (unique constraint on customer_id).

Customer EAV Attribute

AttributeTypePurpose
approve_accountint (boolean)Controls whether a customer can log in. 1 = approved, 0 = pending/blocked. Visible in Admin > Customer grid and form.

Default Roles

Installed automatically via data patch:

Role IDNamePermissions
1Company Adminall
2Company Managermanage_users, view_orders
3Company Buyerplace_order

CMS Page

A placeholder CMS page is created at URL key company-terms (Company Terms and Conditions). Edit its content via Admin > Content > Pages before going live.


Configuration

Path: Stores > Configuration > Orangecat > Company (B2B)

Email Notification

FieldDescriptionDefault
Enable New Company NotificationSend email to admin(s) when a new company is registeredNo
Notification Email AddressComma-separated list of recipient email addresses
Email TemplateTemplate for the admin notificationNew Company Registration Notification
Company - New Account No Password TemplateEmail sent to the company admin when their account is created (no password set)New Company Customer - No Password
Company - Status Change TemplateEmail sent to the company email when its status changesCompany Status Change Notification

Config paths:

mycompany/email/enable_email_notification
mycompany/email/notification_email
mycompany/email/email_template
mycompany/email/company_no_password_template
mycompany/email/company_status_change_template

Customers

FieldDescriptionDefault
Allow Frontend Customer RegistrationIf No, hides "Create an Account" and blocks /customer/account/create (returns 404)No
Require Approval for CustomerIf Yes, newly registered customers start with approve_account = 0 and cannot log in until manually approved. Only available when registration is allowed.Yes

Config paths:

mycompany/customers/allow_frontend_customer_registration
mycompany/customers/require_approval_for_customer

Store Admin Guide

Managing Companies

Path: Admin menu > Companies > Companies

The company grid supports:

  • Inline editing of company name, email, and status
  • Full create/edit form with all company fields and customer assignment

Company Statuses

StatusValueMeaning
Pending0Submitted via frontend, awaiting review
Approved1Active — associated customers can log in
Suspended2Temporarily blocked
Rejected3Registration denied

Changing status to Approved/Suspended/Rejected triggers the Status Change email to the company's email address (if the template is configured).

Company Form Fields

FieldRequiredNotes
Company NameYesDisplay name
Legal NameNoLegal/registered name
Company EmailYesMust be unique. Must differ from the admin's email.
Tax / VAT IDNoMust be unique if provided
Address, City, Region, Postal Code, CountryNo
TelephoneNo
StatusYesSee statuses above

Assigning Customers to a Company

From the Company edit form, use the Customer Assignment section to select a customer as the Company Admin via a grid chooser. The customer is linked with Role ID 1 (Company Admin).

Alternatively, open any Customer in Admin > Customers > All Customers and use the Company Assignment tab:

  • Select a company using the radio-button grid
  • Assign a role from the dropdown
  • Click Save Customer

Business rules enforced on save:

  1. A company can have only one Company Admin (Role ID 1). Attempting to assign a second admin is blocked.
  2. A company must always have one Admin. Changing the only admin's role or removing them is blocked. Assign a replacement admin first.

Approving Customers

When Require Approval for Customer is enabled, new registrations set approve_account = 0 (and force logout to prevent auto-login).

To approve:

  1. Admin > Customers > All Customers
  2. Open the customer
  3. Set Approve Account to Yes
  4. Save

Unapproved customers attempting to log in see:

"Your account is not enabled or your company has not yet been enabled."


Frontend User Guide

Company Registration

Guests can register a new company at: /company/account/create

The "Create a Company" link appears in the header for guests (not visible when logged in).

Registration form fields:

SectionFields
Company InformationCompany Name, Legal Name, Company Email, Tax ID, Address, City, Region, Postal Code, Country, Telephone
Company AdministratorFirst Name, Last Name, Email

Validations applied:

  • Company email and admin email cannot be the same
  • Admin email must not already exist as a customer
  • Company email must be unique (no existing company with same email)
  • Tax ID must be unique (if provided)

After submission, the company is created with Pending status. The admin's customer account is created without a password. A confirmation page is shown and an email is sent to the admin(s) if notification is enabled.


Company User Management (Company Admin only)

Accessible via Account Dashboard > Company Users — visible only to users with the Company Admin role.

Available actions:

  • List users — shows all members of the company with name, email, role, and status
  • Add user — create a new customer account and link it to the company
  • Edit user — change name, email, or role
  • Toggle status — enable or disable a user's approve_account flag
  • Delete user — permanently removes the customer account

Non-admin company members are redirected to the account dashboard if they try to access this section.


Developer Guide

Module Structure

Orangecat/Company/
├── Api/                          Service contracts (interfaces)
│   ├── CompanyRepositoryInterface.php
│   ├── CompanyManagementInterface.php
│   ├── RoleRepositoryInterface.php
│   └── Data/
│       ├── CompanyInterface.php
│       ├── CompanyCustomerInterface.php
│       ├── RoleInterface.php
│       └── CompanySearchResultsInterface.php
├── Block/
│   ├── Account/                  Frontend: registration link + create form
│   └── Adminhtml/               Admin: company + customer tab blocks
│       ├── Company/Edit/
│       └── Edit/Tab/
├── Controller/
│   ├── Account/                  company/account/* routes
│   ├── Users/                    company/users/* routes
│   └── Adminhtml/Company/        mycompany/* admin routes
├── Model/                        Entities, repositories, config
├── Observer/                     Auto-approve + admin save
├── Plugin/                       Login, registration, Hyvä integration
├── Setup/Patch/Data/             EAV attribute + default roles + T&C page
├── Ui/Component/                 UI form data providers and modifiers
└── view/
    ├── adminhtml/                Admin UI components and layouts
    └── frontend/
        ├── layout/               Luma, Breeze (breeze_*), Hyvä (hyva_*) handles
        ├── templates/            Luma + Breeze + Hyvä (hyva/) templates
        ├── email/                Transactional email templates
        └── web/css/hyva/         Hyvä-specific CSS

Service Contracts

CompanyRepositoryInterface

save(CompanyInterface $company): CompanyInterface
get(int $companyId): CompanyInterface
getList(SearchCriteriaInterface $searchCriteria): CompanySearchResultsInterface
delete(CompanyInterface $company): bool
deleteById(int $companyId): bool

CompanyManagementInterface

assignCustomer(int $companyId, int $customerId, int $roleId, array $data = []): bool
removeCustomer(int $customerId): bool
getCompanyIdByCustomerId(int $customerId): ?int
getRoleIdByCustomerId(int $customerId): ?int
isCompanyAdmin(int $customerId): bool
validateManageUser(int $adminId, ?int $targetUserId): void  // throws LocalizedException

RoleRepositoryInterface

Standard CRUD + getList for RoleInterface.


Key Models

Orangecat\Company\Model\Company

Extends AbstractModel. Constants:

Company::STATUS_PENDING    = 0
Company::STATUS_APPROVED   = 1
Company::STATUS_SUSPENDED  = 2
Company::STATUS_REJECTED   = 3

Orangecat\Company\Model\Config

Helper for reading all module config values. Inject and use:

$config->isFrontendCustomerRegistrationAllowed(): bool
$config->isCustomerApprovalRequired(): bool
$config->isNotificationEnabled(): bool
$config->getNotificationEmail(): string
$config->getEmailTemplate(): string
$config->getCompanyNoPasswordEmailTemplate(): string
$config->getCompanyStatusChangeEmailTemplate(): string
$config->isCompanyUser(int $customerId): bool
$config->isCompanyRegistrationContext(): bool

Plugins

PluginTargetTypePurpose
RegistrationRestrictionCustomer\Controller\Account\Create & CreatePostbeforeThrows 404 if registration is disabled
RegisterLinkCustomer\Block\Account\RegisterLinkafterHides "Create an Account" if registration is disabled
CompanyRegisterLinkVisibilityBlock\Account\CompanyRegisterLinkafterControls "Create a Company" link visibility for guests
CustomerRegistration (Hyvä)Hyva\Theme\ViewModel\CustomerRegistrationafterHides registration via Hyvä's ViewModel when disabled
LoginPostCustomer\Controller\Account\LoginPostaroundBlocks login for unapproved customers
CustomerRepositoryInterfacePluginCustomerRepositoryInterfacearoundPrevents deletion of a company admin
CustomerRepositoryInterfaceSavePluginCustomerRepositoryInterfaceafterPersists company assignment data on customer save
TransportBuilderPluginMail\Template\TransportBuilderaroundSwaps email template for company users (no-password flow)

Observers

ObserverEventAreaPurpose
AutoApproveCustomercustomer_register_successfrontendSets approve_account = 1 or 0 based on config. Forces logout if not approved.
SaveCompanyObserveradminhtml_customer_save_afteradminhtmlReads customer[company_id] and customer[role_id] from POST and saves the company link. Enforces single-admin and mandatory-admin rules.

Adding Hyvä Layout Support

Hyvä-specific layout handles use the hyva_ prefix. This module provides:

hyva_default.xml                   — "Create a Company" header link + CSS
hyva_customer_account_login.xml    — Login page adjustments
hyva_company_users_index.xml       — Users list page
hyva_company_users_create.xml      — Create user page
hyva_company_users_edit.xml        — Edit user page

Templates for Hyvä are under view/frontend/templates/hyva/ and view/frontend/templates/users/edit_hyva.phtml / list_hyva.phtml.

Do not put Hyvä templates in view/hyva/ — this project uses view/frontend/templates/hyva/ as the convention.


Email Templates

Template IDFileTrigger
mycompany_email_email_templatenew_company.htmlNew company registered (sent to store admin)
mycompany_email_company_no_password_templatecompany_account_new_no_password.htmlCompany admin account created without password
company_user_welcomecompany_user_welcome.htmlNew company user added
mycompany_email_company_status_change_templatecompany_status_change.htmlCompany status changed

Templates are in view/frontend/email/. Customize via Admin > Marketing > Email Templates.


ACL Resources

Resource IDTitleLocation
Orangecat_Company::company_manageCompany ManagementAdmin top-level
Orangecat_Company::companyCompaniesUnder Company Management
Orangecat_Company::configCompany SettingsUnder Stores > Settings

REST API

All endpoints require admin authorization (Orangecat_Company::company resource).

Endpoints

MethodURLAction
POST/V1/mycompany/Create company
PUT/V1/mycompany/:entity_idUpdate company
GET/V1/mycompany/:companyIdGet company by ID
DELETE/V1/mycompany/:companyIdDelete company
GET/V1/mycompany/Search companies (with searchCriteria)

Example: Create Company

curl -X POST https://your-store.test/rest/V1/mycompany/ \
  -H "Authorization: Bearer <admin_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "company": {
      "name": "Acme Corp",
      "email": "billing@acme.com",
      "tax_id": "US12345678",
      "status": 1
    }
  }'

Example: Search with Filter

GET /V1/mycompany/?searchCriteria[filter_groups][0][filters][0][field]=status
    &searchCriteria[filter_groups][0][filters][0][value]=1
    &searchCriteria[filter_groups][0][filters][0][condition_type]=eq

Frontend Routes Reference

RouteControllerAccess
GET /company/account/createController\Account\CreateGuests only
POST /company/account/createPostController\Account\CreatePostGuests only
GET /company/account/successController\Account\SuccessPublic
GET /company/usersController\Users\IndexCompany Admin only
GET /company/users/createController\Users\CreateCompany Admin only
POST /company/users/saveController\Users\SaveCompany Admin only
GET /company/users/editController\Users\EditCompany Admin only
POST /company/users/deleteController\Users\DeleteCompany Admin only
POST /company/users/statusController\Users\StatusCompany Admin only

DevOps & Integrator Notes

Deployment Checklist

# After deploying or updating this module:
bin/magento module:enable Orangecat_Company
bin/magento setup:upgrade          # runs db_schema.xml migrations + data patches (EAV, roles, CMS page)
bin/magento setup:di:compile       # regenerates interceptors and proxies
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

Integration Token Scope

Minimum permissions for an ERP or external integration reading company data:

  • Orangecat_Company::company
  • Orangecat_Company::company_manage (parent required)

Disabling Without Uninstalling

Warning: all dependent modules (Orangecat_CompanyCredit, Orangecat_CompanyMethods, Orangecat_Prices, etc.) must be disabled first.

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

Data Integrity

  • mycompany_customer enforces a unique constraint on customer_id — one company per customer.
  • Deleting a company does not automatically delete linked customers; only the mycompany_customer link row is removed.
  • The approve_account EAV attribute persists after module disable. Re-enabling the module restores the approval gate.
  • The company-terms CMS page is created by data patch and is not removed on module disable or uninstall.