mar-pod-b2b / module-b2b-sales-representative
Company sales-representative assignment and audited assisted selling for Marpod B2B Advanced.
Package info
gitlab.com/mar-pod-b2b/module-b2b-sales-representative
Type:magento2-module
pkg:composer/mar-pod-b2b/module-b2b-sales-representative
Requires
- php: ^8.5
- magento/framework: ^103.0
- magento/module-backend: ^102.0
- magento/module-customer: ^103.0
- magento/module-quote: ^101.2
- magento/module-webapi: ^100.4
- mar-pod-b2b/module-b2b-company: ^1.0
- mar-pod-b2b/module-b2b-core: ^1.0
- mar-pod-b2b/module-b2b-quote: ^1.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Company-to-admin sales representative assignment, a portfolio-restricted Companies grid, internal notes/tasks, and an audited assisted-selling service that never inherits the customer's session.
Status
Full assignment/portfolio engine and Admin UI shipped.
Implemented foundation
- declarative schema:
marpod_b2b_sales_rep_assignment(company × admin_user, unique, withis_primary/is_activeflags),marpod_b2b_sales_rep_note(company-scoped internal notes),marpod_b2b_sales_rep_task(company-scoped tasks with a due date and done flag); SalesRepPortfolioResolverInterface::getAssignedCompanyIds()/isAssignedToCompany()— the single source of truth for "which companies is this admin responsible for";- restricted Companies grid:
RestrictCompanyGridToPortfolioPluginfilters the baseMarpod_B2bCompanyadmin grid to an admin's assigned companies unless they hold theMarpod_B2bSalesRepresentative::view_all_companiesACL resource. It targets the sharedMagento\Framework\View\Element\UiComponent\DataProvider\SearchResultbase class (guarded to the Companies grid at runtime via the collection's main table) rather than theMarpodB2bCompanyGridCollectionvirtualType name directly — declaring a<virtualType>for that name in one module and a<type>plugin target of the same name in another was found to silently break DI compilation of the virtualType (fixed in 1.1.1; see the module's git history forRestrictCompanyGridToPortfolioPluginif implementing a similar cross-module grid plugin); AssistedSellingServiceInterface::createCartForCustomer()/createQuoteForCustomer()— creates a cart or quote "on behalf of" a customer without ever inheriting their session: it takes an explicit$customerIdand drives session-independent primitives directly (CartManagementInterface::createEmptyCartForCustomer()/getCartForCustomer(),QuoteRepositoryInterface, the frozenMarpod_B2bQuote\Api\QuoteItemRepositoryInterface) — never the session-boundMarpod_B2bQuote\Api\QuoteManagementInterface::createFromCart(). Authorization goes through the portfolio resolver first (LocalizedExceptionif the acting admin is not assigned to the customer's company);- every assisted action is logged through the existing, frozen
Marpod\B2bCore\Api\Audit\AuditLoggerInterface— withactorCustomerId = null(the same "null = admin/system" conventionPurchaseRequestWorkflowInterface::transition()already uses) and the acting admin's identity plusimpersonation: truerecorded in the event's free- formmetadata, sinceAuditEventInterfacehas no dedicated admin-actor field.
Admin UI
Marpod_B2bSalesRepresentative::manage (marpod_b2b_sales_representative/assignment/index)
provides assignment management with native Magento General, Notes, and Tasks tabs. Notes and
Tasks use independent filterable and pageable embedded grids; their add forms are separated below
the grids, and every related POST action restores the originating tab.
Assignments are an Admin/CRM concern. Their PHP service contracts remain the source of truth for
integrations; a storefront GraphQL surface is intentionally not exposed because admin-user
identity and internal notes/tasks are not customer-facing data. ACL-protected REST CRUD/search for
assignments is available under /V1/marpod-b2b/sales-rep-assignments; notes and tasks remain
internal until a concrete CRM consumer and its field-level permissions are defined.
Requirements
- PHP 8.5
- Magento 2.4.9-compatible framework packages
mar-pod-b2b/module-b2b-core,mar-pod-b2b/module-b2b-company,mar-pod-b2b/module-b2b-quote
Installation
Run from the Magento project root:
composer require mar-pod-b2b/module-b2b-sales-representative:^1.1
bin/magento module:enable Marpod_B2bSalesRepresentative
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:clean
Development
The planned scope, dependency rules, cache boundaries, security requirements, and test strategy
are documented in packages/B2B_LIGHT_PLAN.md in the development Magento project (section 9.7).
Unit tests:
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist packages/module-b2b-sales-representative/Test/Unit
Admin smoke test:
cd packages/module-b2b-sales-representative/Test/Playwright
npm install
npm test
Limitations
- no email/notification dispatch for due-soon tasks;
- a company can have multiple
is_primaryassignments simultaneously — the schema does not enforce exactly one primary rep per company, only uniqueness per company+admin pair.
Uninstallation
Do not remove the package while another installed module requires it. The
marpod_b2b_sales_rep_* tables contain business data and are retained when the module is
disabled or its package is removed; removing it also removes the Companies-grid restriction, so
every admin sees every company again.