orangecat / module-company-sales-rep
Assigns a Magento admin user as sales representative to a B2B company and displays contact details on the customer dashboard
Package info
github.com/olivertar/m2_companysalesrep
Type:magento2-module
pkg:composer/orangecat/module-company-sales-rep
Requires
- php: >=8.1
- magento/framework: *
- orangecat/module-company: *
README
Assigns a Magento admin user as a sales representative to a B2B company and displays their contact details on the customer account dashboard.
Module: Orangecat_CompanySalesRep
Version: 1.0.0
License: OSL-3.0
Author: Oliverio Gombert olivertar@gmail.com
Table of Contents
- Overview
- Theme Compatibility
- Requirements
- Installation
- What Gets Installed
- Configuration
- Store Admin Guide
- Company Member Guide (Frontend)
- Developer Guide
- REST API
- Frontend Routes Reference
- DevOps & Integrator Notes
Overview
Orangecat_CompanySalesRep extends Orangecat_Company to allow store admins to assign a designated admin user as the sales representative for each B2B company. Company members can then see their rep's name, email, telephone, and WhatsApp directly on the customer account dashboard.
The module handles:
- Adding a Sales Representative dropdown to the company edit form in the admin
- Extending the admin user edit form with Telephone and WhatsApp contact fields
- Persisting the assignment via a foreign-key column on the
mycompanytable - Rendering a Sales Representative contact card on the customer account dashboard (Luma and Hyvä themes)
Position in the Orangecat B2B Dependency Chain
Orangecat_Core (via composer: orangecat/core)
└── Orangecat_Company
├── Orangecat_Prices
│ ├── Orangecat_PricesList
│ └── Orangecat_PricesCompany
├── Orangecat_CompanyCredit
├── Orangecat_CompanyMethods
├── Orangecat_CompanySalesRep ← this module
└── Orangecat_PurchaseOrder
Orangecat_Company and Magento_User must both be installed and enabled before this module.
Theme Compatibility
| Theme | Status | Notes |
|---|---|---|
| Luma | Supported | Dedicated template sales_rep.phtml. Uses standard .box markup. Layout handle customer_account_index.xml. |
| Hyvä | Supported | Dedicated template sales_rep_hyva.phtml with Tailwind CSS card layout. Layout handle hyva_customer_account_index.xml. |
| Breeze Evolution | Partial | No dedicated Breeze layout. Falls back to the Luma template via customer_account_index.xml, which Breeze inherits. Functional but unstyled in Breeze card conventions. Add a breeze_customer_account_index.xml layout and a dedicated template to apply Breeze-native styling. |
Requirements
| Dependency | Version / Notes |
|---|---|
| Magento | 2.4.x |
| PHP | >= 8.1 |
Orangecat_Company |
Must be enabled first |
Magento_User |
Core admin user module (bundled with Magento) |
magento/framework |
Bundled with Magento |
Installation
Via Git Submodule (recommended for this project)
# From repo root
git submodule add git@github.com:olivertar/m2_company_sales_rep.git app/code/Orangecat/CompanySalesRep
git submodule update --init --recursive
Enable the Module
Run inside the PHP container (reward shell):
bin/magento module:enable Orangecat_CompanySalesRep bin/magento setup:upgrade bin/magento setup:di:compile bin/magento setup:static-content:deploy -f bin/magento cache:flush
What Gets Installed
Database Columns
This module does not create new tables. It adds columns to two existing tables.
mycompany (extended from Orangecat_Company)
| Column | Type | Nullable | Notes |
|---|---|---|---|
sales_rep_id |
INT UNSIGNED |
Yes | FK → admin_user.user_id. Set to NULL on admin user delete. |
admin_user (core Magento table)
| Column | Type | Nullable | Notes |
|---|---|---|---|
telephone |
VARCHAR(50) |
Yes | Sales rep phone number, used for tel: links. |
whatsapp |
VARCHAR(50) |
Yes | Sales rep WhatsApp number, used for wa.me/ links. |
EAV Attributes
None.
Data Patches
None. No default records, roles, or CMS pages are created.
Configuration
This module has no system configuration (no entries in core_config_data). All settings are per-entity.
Per-Company Setting
| Field | Storage | Notes |
|---|---|---|
| Sales Representative | mycompany.sales_rep_id |
Set in the company edit form under the General fieldset. |
Per-Admin User Settings
| Field | Storage | Notes |
|---|---|---|
| Telephone | admin_user.telephone |
Set in the admin user edit form. Used for tel: links on frontend. |
admin_user.whatsapp |
Set in the admin user edit form. Used for https://wa.me/ links on frontend. |
Store Admin Guide
Assigning a Sales Representative to a Company
- Navigate to Companies > Companies (or the path defined by
Orangecat_Company). - Open a company record.
- In the General fieldset, locate the Sales Representative dropdown.
- Select the admin user to assign. The list shows all active admin users as
"First Last (username)". Select -- Unassigned -- to remove a rep. - Save the company.
The dropdown only lists currently active admin users. If an admin user is deactivated or deleted after assignment,
sales_rep_idis automatically set toNULL(via theON DELETE SET NULLforeign key constraint), and the sales rep card will no longer appear on the customer dashboard.
Adding Contact Details to an Admin User
- Navigate to System > Permissions > All Users.
- Open the admin user record.
- In the Account Information tab, locate the Telephone and WhatsApp fields added by this module.
- Enter the contact details and save.
These fields are optional. Only fields with values are rendered on the customer dashboard.
Company Member Guide (Frontend)
Sales Representative Card
Company members who are logged in can view their assigned sales representative's contact information on the My Account dashboard.
URL: /customer/account/
If a sales rep has been assigned to the company, a Sales Representative card is displayed alongside the standard account information blocks. The card shows:
- Name — rep's first and last name
- Email — clickable
mailto:link - Telephone — clickable
tel:link (non-numeric characters stripped for the href) - WhatsApp — clickable
https://wa.me/link (digits only in the href)
Fields are only shown if they contain a value. The card does not appear if:
- No sales rep has been assigned to the company.
- The assigned admin user has been deactivated or deleted.
- The logged-in customer does not belong to a company.
Developer Guide
Module Structure
CompanySalesRep/
├── Block/
│ └── Customer/Account/Dashboard/
│ └── SalesRep.php # Frontend block — loads and exposes sales rep data
├── Model/
│ └── Source/
│ └── AdminUsers.php # OptionSourceInterface — dropdown options for company form
├── Plugin/
│ ├── CompanyDataProviderPlugin.php # afterGetData — injects sales_rep_id into company form
│ ├── CompanyRepositoryPlugin.php # beforeSave — persists sales_rep_id from request
│ └── User/Edit/Tab/
│ └── MainPlugin.php # afterGetForm — adds telephone/whatsapp to admin user form
├── etc/
│ ├── adminhtml/
│ │ └── di.xml # Plugin registrations (adminhtml scope)
│ ├── db_schema.xml # Column additions to mycompany and admin_user
│ └── module.xml # v1.0.0, depends on Orangecat_Company + Magento_User
├── view/
│ ├── adminhtml/
│ │ └── ui_component/
│ │ └── mycompany_company_form.xml # Adds sales_rep_id field to company form
│ └── frontend/
│ ├── layout/
│ │ ├── customer_account_index.xml # Luma: adds SalesRep block to dashboard
│ │ └── hyva_customer_account_index.xml # Hyvä: adds SalesRep block with Hyvä template
│ └── templates/account/dashboard/
│ ├── sales_rep.phtml # Luma template — .box markup
│ └── sales_rep_hyva.phtml # Hyvä template — Tailwind card
├── registration.php
└── composer.json
Key Classes
| Class | Role |
|---|---|
Block\Customer\Account\Dashboard\SalesRep |
Extends Template. Lazy-loads sales rep from session + company + admin_user. Exposes hasSalesRep(), getSalesRepName(), getSalesRepEmail(), getSalesRepTelephone(), getSalesRepWhatsApp(). |
Model\Source\AdminUsers |
Implements OptionSourceInterface. Returns all active admin users sorted by first name as [['value' => id, 'label' => 'First Last (username)']]. Includes an "-- Unassigned --" option with empty value. |
SalesRep Block — Public Methods
public function hasSalesRep(): bool public function getSalesRepName(): string public function getSalesRepEmail(): string public function getSalesRepTelephone(): string public function getSalesRepWhatsApp(): string
Observers
None. This module registers no observers.
Plugins
| Plugin Class | Target | Hook | Purpose |
|---|---|---|---|
Plugin\CompanyDataProviderPlugin |
Orangecat\Company\Ui\Component\Form\Company\DataProvider |
afterGetData |
Reads sales_rep_id from CompanyRepository and injects it into the company form data array. |
Plugin\CompanyRepositoryPlugin |
Orangecat\Company\Api\CompanyRepositoryInterface |
beforeSave |
Reads sales_rep_id from the current HTTP request and sets it on the company object before persistence. Converts empty string to null. |
Plugin\User\Edit\Tab\MainPlugin |
Magento\User\Block\User\Edit\Tab\Main |
afterGetForm |
Appends telephone and whatsapp text fields to the admin user edit form. Re-applies model data to populate saved values. |
All three plugins are registered in etc/adminhtml/di.xml (adminhtml scope only).
JS Components
None. This module has no custom JavaScript.
Email Templates
None. This module sends no emails.
ACL Resources
None. This module defines no ACL resources. Access to the company form and admin user form is governed by Orangecat_Company and Magento_User ACL respectively.
Adding Custom Logic
- Add more contact fields: Extend
db_schema.xmlto add columns toadmin_user, add fields inMainPlugin, and add getter methods toSalesRepblock. No new templates needed if you add output to existing.phtmlfiles. - Filter sales rep options: Extend or replace
Model\Source\AdminUsersvia DI preference to restrict the dropdown (e.g., by admin role or custom attribute). - Override the dashboard card: Override
sales_rep.phtmlorsales_rep_hyva.phtmlin your theme's template directory atOrangecat_CompanySalesRep/account/dashboard/.
REST API
This module exposes no REST API endpoints. Sales rep assignment is managed exclusively through the admin UI. The sales_rep_id field is available on the company object retrieved via Orangecat_Company REST endpoints (it is a raw data field on the company model).
Frontend Routes Reference
This module defines no frontend routes. The sales rep card is rendered as a block within the existing /customer/account/ page via layout XML.
DevOps & Integrator Notes
Deployment Checklist
# Inside reward shell (PHP container) bin/magento module:enable Orangecat_CompanySalesRep bin/magento setup:upgrade # applies db_schema.xml column additions bin/magento setup:di:compile bin/magento setup:static-content:deploy -f bin/magento cache:flush
Integration Token Scope
This module adds no ACL resources. To manage company sales rep assignments via the Orangecat_Company REST API, the integration token requires whatever ACL the Company module mandates for company save operations.
Disabling Without Uninstalling
bin/magento module:disable Orangecat_CompanySalesRep bin/magento cache:flush
Disabling hides the sales rep card from the dashboard and removes the Sales Representative field from the company form. The database columns (mycompany.sales_rep_id, admin_user.telephone, admin_user.whatsapp) are retained — no data loss.
Data Integrity Notes
mycompany.sales_rep_idhas anON DELETE SET NULLforeign key toadmin_user.user_id. Deleting an admin user automatically clears the assignment on all companies without orphaning records.- The two new columns on
admin_user(telephone,whatsapp) are nullable with no unique constraint. They persist independently of whether the module is enabled. - No cascade deletes. Disabling or uninstalling the module does not remove these columns automatically — use
bin/magento setup:db-declaration:generate-patchand a custom schema patch if column removal is needed.