How To Create Adobe Commerce B2B Customer Account & Company Account Programmatically

The following below code need to put in your custom module controlller

Here We are creating

[1] – Adobe Commerce B2B Customer Account

[2] – Adobe Commerce B2B Company Account

<?php
/*
 * John_Customercompanycreation

 * @category   Adobe Commerce B2B Customer Company Account Creation
 * @package    Customerregister Form
 * @copyright  Copyright (c) 2023 - Mage2DB.com
 * @Email      johndusa1021@gmail.com
 * @version    1.0.0
 */
namespace John\Customercreation\Controller\Index;

use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Framework\Message\ManagerInterface as MessageManagerInterface;
use Magento\Customer\Model\CustomerFactory;
use Magento\Company\Api\CompanyRepositoryInterface;
use Magento\Company\Api\Data\CompanyInterface;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Customer\Api\CustomerRepositoryInterface;

class Index extends \Magento\Framework\App\Action\Action
{
    /**
     * @var \Magento\Framework\App\RequestInterface
     */
    protected $request;

    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var John\Customerregister\Helper\Data
     */
    protected $helper;

    /**
     * @var \Magento\Framework\Controller\Result\RedirectFactory
     */
    protected $resultRedirectFactory;

    /**
     * @var \Magento\Framework\Message\ManagerInterface
     */
    protected $messageManager;

    /**
     * @var \Magento\Customer\Model\CustomerFactory
     */
    protected $customerFactory;

  
    /**
     * @var \Magento\Company\Api\CompanyRepositoryInterface
     */

    protected $companyRepository;

    /**
     * @var \Magento\Company\Api\Data\CompanyInterface
     */

    protected $companyInterface;

    /**
     * @var \Magento\Framework\Api\DataObjectHelper
     */

    protected $objectHelper;

    /**
     * @var CustomerRepositoryInterface
     */
    protected $customerRepository;

    /**
     * @param Action\Context $context
     * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
     * @param \Magento\Framework\App\Cache\StateInterface $cacheState
     * @param \Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Magento\Company\Api\CompanyRepositoryInterface $companyRepository
     * @param \Magento\Company\Api\Data\CompanyInterface $companyInterface
     * @param \Magento\Framework\Api\DataObjectHelper $objectHelper
     */

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        RequestInterface $request,
        StoreManagerInterface $storeManager,
        RedirectFactory $resultRedirectFactory,
        MessageManagerInterface $messageManager,
        CustomerFactory $customerFactory,
        CompanyRepositoryInterface $companyRepository,
        CompanyInterface $companyInterface,
        DataObjectHelper $objectHelper,
        CustomerRepositoryInterface $customerRepository
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
        $this->request = $request;
        $this->storeManager = $storeManager;
        $this->resultRedirectFactory = $resultRedirectFactory;
        $this->messageManager = $messageManager;
        $this->customerFactory = $customerFactory;
        $this->companyRepository = $companyRepository;
        $this->companyInterface = $companyInterface;
        $this->objectHelper = $objectHelper;
        $this->customerRepository = $customerRepository;
    }

    /**
     * Flush cache storage
     *
     */
    public function execute()
    {
        try {
            /* start: To Save Data in Customer_Entity Database Table -- Customer Registration Process*/
            $websiteId = $this->storeManager->getWebsite()->getWebsiteId();

            $firstName = "John";
            $lastName = "Doe";
            $email = "smith@mage2db.com";
            $password = "R@]*H7~>giXo16Cxv5+n%Mt";

            // instantiate customer object
            $customer = $this->customerFactory->create();
            $customer->setWebsiteId($websiteId);

            if ($customer->loadByEmail($email)->getId()) {
                //echo 'Customer with the email ' . $email . ' is already registered.';
                $message = __(
                    'There is already an account with this email address "%1".',
                    $email
                );
                // @codingStandardsIgnoreEnd
                $this->messageManager->addError($message);
            } else {
                try {
                    // prepare customer data
                    $customer->setEmail($email);
                    $customer->setFirstname($firstName);
                    $customer->setLastname($lastName);

                    // set null to auto-generate password
                    $customer->setPassword($password);

                    // set the customer as confirmed
                    // this is optional
                    // comment out this line if you want to send confirmation email
                    // to customer before finalizing his/her account creation
                    $customer->setForceConfirmed(true);

                    // save data
                    $customer->save();

                    // send welcome email to the customer
                    $customer->sendNewAccountEmail();

                    /* Finish: To Save Data in Customer_Entity Database Table -- Customer Registration Process */
                    /*Start: To Get Customer ID By Email*/
                    $customerData = $this->customerRepository->get($email);
                    $customerId_latest = (int) $customerData->getId();

                    /*Finish: To Get Customer ID By Email*/
                    /* Starts To Save Customer Company Details -- Customer Registration Process -- Once Customer Account Created */
                    /* To Create Customer Company require Customer entity_id , that only done after customer account Creation */
                    /* Customer entity_id  here using as super_user_id*/

                    if (isset($customerId_latest) &&  !empty($customerId_latest) ):

                        $companyRepo = $this->companyRepository;
                        $companyObj = $this->companyInterface;
                        $dataObj = $this->objectHelper;

                        $company = [
                            "company_name" => "Google",
                            "company_email" => "info@mage2db.com",
                            "street" => ["D-101, New York"],
                            "city" => "New York",
                            "country_id" => "US",
                            "region" => "CA",
                            "region_id" => "12",
                            "postcode" => "10001",
                            "telephone" => "9999999999",
                            "super_user_id" => $customerId_latest,
                            "customer_group_id" => 1,
                        ];

                        /*Super ID getting from customer_entity table*/
                        /*Once Customer Created, it ID as super_user_id for Company account*/
                        $this->objectHelper->populateWithArray(
                            $this->companyInterface,
                            $company,
                            \Magento\Company\Api\Data\CompanyInterface::class
                        );

                        $this->companyRepository->save($this->companyInterface);
                    endif;
                    /*Finish To Save Customer Company Details -- Customer Registration Process -- Once Customer Account Created*/

                    $this->messageManager->addSuccess(
                        __(
                            "Customer Company account with email %1 created successfully.",
                            $email
                        )
                    );

                    $url = $this->urlModel->getUrl("*/*/add", [
                        "_secure" => true,
                    ]);
                    $resultRedirect->setUrl($this->_redirect->success($url));

                    //$resultRedirect->setPath('*/*/');
                    return $resultRedirect;
                } catch (StateException $e) {
                    $url = $this->urlModel->getUrl(
                        "customer/account/forgotpassword"
                    );
                    // @codingStandardsIgnoreStart
                    $message = __(
                        'There is already an account with this email address. If you are sure that it is your email address, <a href="%1">click here</a> to get your password and access your account.',
                        $url
                    );
                    $this->messageManager->addError($message);
                } catch (InputException $e) {
                    $this->messageManager->addError(
                        $this->escaper->escapeHtml($e->getMessage())
                    );
                    foreach ($e->getErrors() as $error) {
                        $this->messageManager->addError(
                            $this->escaper->escapeHtml($error->getMessage())
                        );
                    }
                } catch (LocalizedException $e) {
                    $this->messageManager->addError(
                        $this->escaper->escapeHtml($e->getMessage())
                    );
                } catch (\Exception $e) {
                    //$this->messageManager->addException($e, __('We can\'t save the customer.'));
                }
            }
            // Finish: To Save Data in Customer_Entity Database Table
            //Finish: To save Customer Company Details
        } catch (LocalizedException $e) {
            $this->messageManager->addErrorMessage($e->getMessage());
        } catch (\Exception $e) {
            $this->messageManager->addErrorMessage(
                __("Something went wrong, please try again.")
            );
        }

        $this->resultPage = $this->resultPageFactory->create();
        return $this->resultPage;
    }
}   

Once script run the following set of email by Customer

Step [1] – Customer Registration welcome email ::

Customer smith@mage2db.com getting email from Adobe Commerce B2B Store Owner Email Johndusa1021@gmail.com

Step [2] – Go To Adobe Commerce B2B admin

Left Side Menu –> Customers –> Customers –> Companies

Step [3] – Once clicked on companies –> display listing of all customer companies listing

By Default newly created company disabled,

As below screenshot newly created company Google as Pending Approval Stage

[3.1] – Customer Email smith@mage2db.com store in database table customer_entity
As I have explained It’s entity_id works as super_user_id for creating Customer company account in database Table company

[3.2] – info@mage2db.com store in database table company

Here we have created Both Adobe Commerce B2B Customer Account & Customer Company account

First Created Adobe Commerce B2B Customer Account, once got customer created account entity_id from Database Table customer_entity

Once got entity_id from Database Table customer_entity , we are using that entity_id as super_user_id during Adobe Commerce B2B Customer Company account creating

Note:: if you want to create only Adobe Commerce B2B Customer Company account

[3.3] – As Here Newly created company Google Pending Approval Condition ,

Admin must be activate –> Checked Company Google Row –-> Select Set Active From Actions Drop Down Menu

Clicked on OK to activate Company Google

After Activation Company Status as Active

Step [4] – After activation Company

Customer will be getting email on his registered email

Here Customer smith@mage2db.com

got email from Adobe Commerce B2B Store Owner johndusa1021@gmail.com

Step [4] – Finally Customer smith@mage2db.com can login

[4.1] – Once Logged In, Customer smith@mage2db.com can view his Dashboard

[4.2] – Once you clicked on Customer Profile , you can see Company Email with Legal Address

[4.3] – Once clicked on Company Structure , you can see Company Structure

[4.4] – Once clicked on Company Users, you can see John Doe (smith@mage2db.com) as Company administrator

[4.5] – Once you clicked on Roles and Permissions –> Default Roles

You can create new Role as per your Business Need.

How To Manage Real Time Sales Tax & Use Tax Calculation in Adobe Commerce

In Adobe Commerce to reduce streamline tax determination and compliance by automating tax calculations for every transaction—all backed by the global leader in tax technology

“Adobe Commerce Must Use Vertex Tax Extension”

https://commercemarketplace.adobe.com/vertexinc-vertex-tax-module.html

But these Sales Taxation Calculation changes time to time for every country & its region based , due to this we have to install Adobe Commerce API based Sales Taxation and accurate sales extension so that time to time country & its region-based Sales Taxation Calculation to be reflected in our system to generate correct country & its region-based Invoice with correct tax.

Vertex centralizes all the rates and rules required for product taxability and accurate sales and use tax calculation. No need to manage constantly changing tax content manually

How To Create Adobe Commerce B2B Customer Company Account Programmatically

The following below code need to put in your custom module controlller

Here We are considering customer account has been already created in Adobe Commerce B2B & it entity_id=25, that is using here as super_user_id=25 & email = userwithoutcompany@gmail.com

<?php
/*
 * John_Customercompanycreation

 * @category   Adobe Commerce B2B Customer Company Account Creation
 * @package    Customerregister Form
 * @copyright  Copyright (c) 2023 - Mage2DB.com
 * @Email      johndusa1021@gmail.com
 * @version    1.0.0
 */
namespace John\Customercreation\Controller\Index;

use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Company\Api\CompanyRepositoryInterface;
use Magento\Company\Api\Data\CompanyInterface;
use Magento\Framework\Api\DataObjectHelper;

class Index extends \Magento\Framework\App\Action\Action
{
    //protected $_modelDataFactory;

    /**
     * @var \Magento\Framework\App\Cache\TypeListInterface
     */
    protected $_cacheTypeList;

    /**
     * @var \Magento\Framework\App\Cache\StateInterface
     */
    protected $_cacheState;

    /**
     * @var \Magento\Framework\App\Cache\Frontend\Pool
     */
    protected $_cacheFrontendPool;

    /**
     * @var \Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    /**
     * @var \Magento\Company\Api\CompanyRepositoryInterface
     */

    protected $companyRepository;

    /**
     * @var \Magento\Company\Api\Data\CompanyInterface
     */

    protected $companyInterface;

    /**
     * @var \Magento\Framework\Api\DataObjectHelper
     */

    protected $objectHelper;

    /**
     * @param Action\Context $context
     * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
     * @param \Magento\Framework\App\Cache\StateInterface $cacheState
     * @param \Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     * @param \Magento\Company\Api\CompanyRepositoryInterface $companyRepository
     * @param \Magento\Company\Api\Data\CompanyInterface $companyInterface
     * @param \Magento\Framework\Api\DataObjectHelper $objectHelper
     */

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
        \Magento\Framework\App\Cache\StateInterface $cacheState,
        \Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool,
        \Magento\Framework\Message\ManagerInterface $messageManager,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Magento\Company\Api\CompanyRepositoryInterface $companyRepository,
        \Magento\Company\Api\Data\CompanyInterface $companyInterface,
        \Magento\Framework\Api\DataObjectHelper $objectHelper
    ) {
        parent::__construct($context);
        $this->_cacheTypeList = $cacheTypeList;
        $this->_cacheState = $cacheState;
        $this->_cacheFrontendPool = $cacheFrontendPool;
        $this->resultPageFactory = $resultPageFactory;
        $this->_messageManager = $messageManager;
        $this->companyRepository = $companyRepository;
        $this->companyInterface = $companyInterface;
        $this->objectHelper = $objectHelper;
    }

    /**
     * Flush cache storage
     *
     */
    public function execute()
    {
        $companyRepo = $this->companyRepository;
        $companyObj = $this->companyInterface;
        $dataObj = $this->objectHelper;

        $company_email = "company@mage2db.com";

        $company = [
            "company_name" => "John",
            "company_email" => "$company_email",
            "street" => ["100 Big Tree Avenue"],
            "city" => "New York",
            "country_id" => "US",
            "region" => "CA",
            "region_id" => "12",
            "postcode" => "1001",
            "telephone" => "9999999999",
            "super_user_id" => 25,
            "customer_group_id" => 1,
        ];

    //Here We are considering customer account has been already created & it entity_id=25
   //It is using here as super_user_id=25 
  //Customer Registered Email userwithoutcompany@gmail.com

        $dataObj->populateWithArray(
            $companyObj,
            $company,
            \Magento\Company\Api\Data\CompanyInterface::class
        );

        try {
            // save customer company details address
            $companyRepo->save($companyObj);

            $this->_messageManager->addSuccess(
                __(
                    "Customer account with email %1 created successfully.",
                    $company_email
                )
            );
        } catch (Exception $e) {
            $this->_messageManager->addException(
                $e,
                __('We can\'t save the customer address.')
            );
        }

        $this->resultPage = $this->resultPageFactory->create();
        return $this->resultPage;
    }
}

Once customer’s company created, need to be by using his registered email

[1] – Customer Registered Email / Password = userwithoutcompany@gmail.com / what you have set

[2] – Once logged, customer can see his Registered Email = userwithoutcompany@gmail.com & role = Company Administrator

[3] – Here, we have created customer registered account by using

Email = userwithoutcompany@gmail.com

Once Customer account created by userwithoutcompany@gmail.com

We have done Customer Company Account Programmatically

Company Email = company@mage2db.com

Finally
Email = userwithoutcompany@gmail.com has Company Administrator
His Company Email=company@mage2db.com

How To Check PHP Coding Security Standards

The Open Worldwide Application Security Project (OWASP) is a nonprofit foundation dedicated to improving software security. It operates under an “open community” model, which means that anyone can participate in and contribute to OWASP-related online chats, projects etc.

For more info

https://owasp.org/www-community/Source_Code_Analysis_Tools

Top 6 PHP Coding Standard or Coding Analysis Tools

Sonarqube: It is main widely-known option for static code analysis. It incorporates thousands of automated code analysis rules, protecting code on multiple fronts, and guiding development teams toward quality. They also provide an IDE extension, Sonar lint which works well to supplement the CI offerings.

PHPStan:: It is a static code analysis tool that focuses on finding errors in the source code without having to actually run it. It catches whole classes of bugs even before you write tests for the code. PHPStan might be the most commonly used tool and also one of the newest.

PHP_CodeSniffer:: It is a very popular tool used for enforcing coding standards in PHP projects. It analyzes your PHP code and reports any violations of predefined standards, helping developers ensure consistent and readable code. It works by basically parsing your PHP code and checking it against a set of rules defined in coding standard rulesets. These rulesets can be based on popular coding standards such as PSR-1, PSR-2, and PSR-12 or customized according to specific project requirements. The tool detects deviations from the coding standards and provides detailed reports.

Pslam:: It is another great static code analysis tool for finding errors in PHP codebases. It was released in 2016 and has grown in popularity a little more slowly than others. This tool also fixes bugs automatically, allowing developers to improve their code without too much extra work.

PHPCheckstyle:: It is a static code analysis tool used in software development. Its main purpose is checking whether PHP source code complies with coding rules. It basically automates the lengthy process of checking code and helps PHP developers enforce coding standards.

Scrutinizer:: It is another widely used analysis tool. It seamlessly integrates into the software development workflow, and continuously builds and deploys application code. It’s free for open-source projects but is only available as a hosted solution. This makes Scrutinizer the most popular option for open-source development.

How To Configure Request For Quote on Shopping Cart Page inAdobe Commerce

If quotes are enabled in the Adobe Commerce B2B Quote Enabled Features configuration, an authorized buyer from a company (User Must be registered as Company) can initiate the price negotiation process by requesting a quote from their shopping cart.

Step [1] – By Default Adobe Commerce B2B , below all things disabled

[a] – Company

[b] – Quick Order

[c] – Requisition List

Step [2] – Once clicked on Enable Company, below two things will be auto displayed

      [a] - Enable Shared Catalog  - By Default Disabled
      [b] - Enable B2B Quote       - By Default Disabled 

Enable Shared Catalog & Enable B2B Quote depends on Enable Company,  Once Enable Company Status = Yes

Step [3] – Registered as New user by Company registration as below

Step [4] – Customer quote request experience


[4.1] – The customer logs in to their user account as a buyer with permission to request a quote.

[4.2] – Adds the products that they want to be included in the quote to the shopping cart.

[4.3] – Clicks Request a Quote.

[4.4] – In the Add your comment box, enters a brief note that describes the request.

[4.3] – Enters a Quote Name.

[4.4] – If needed, attaches a supporting document or image to the quote:

  • Clicks Attach file.
  • Chooses the file from their system.

By default, an attached file can be up to 2 MB, in any of the following file formats: DOC, DOCX, XLS, XLSX, PDF, TXT, JPG or JPEG, PNG.

[4.5] Finally Clicked on Send Request Button

Step [5] – How To Check Request Quote From Admin End

[5.1] – Go To Sales > Quotes

[5.2] – Once Clicked, display all Quotes Listing

[5.3] – Clicked on View to see full details

[5.4] – Finally admin can see each Quote details & reply as per business need.

How To Enable Enable Shared Catalog, Enable B2B Quote in Adobe Commerce B2B in Adobe Commerce B2B

Step [1] – By Default Adobe Commerce B2B , below all things disabled

[a] – Company

[b] – Quick Order

[c] – Requisition List

Step [2] – Once clicked on Enable Company, below two things will be auto displayed

      [a] - Enable Shared Catalog  - By Default Disabled
      [b] - Enable B2B Quote       - By Default Disabled 

Enable Shared Catalog & Enable B2B Quote depends on Enable Company,  Once Enable Company Status = Yes

How Do Company Registration in Adobe Commerce (Cloud or Enterprise) Edition – B2B

Step [1] – Go To Home Page — Here Two options to create a company account

[a] – Create Account –> Create A New Company Account

[b] – Create A Company Account

Step [2] – Once Clicked on Create A New Company Account, It is displayed as —

Step [3] – First Part –Company Information

Step [4] – Second Part – Legal Address

Step [5] – Third Part Company Administrator

Step [6] – Once filled all required entries as

Step [7] – Finally Clicked on Submit Button, all entries have been saved in Database

User’s Email Format

Clicked on Link redirects on Password & Confirm Password setting page.

Once Password & Confirm Password set, it stored in customer_entity table

Company Account Still Not Active–>Only applicable once Admin Activate from admin end, once done email format as

Finally, Company Account has been activated.

Step [8] – How To Activate Company Account By Administrator

[a] – GoTo–> Left Side–>Customers–>Companies

[b] – Display listing of all company details

[c] – How To Activate Registered Companies –> Checked companies that you want to be activate –> Clicked on Set Active

[d] – Once Activate Done email as

The following below details database tables where registered company values store.

Step [9] – Database Table — customer_entity

Step [10] – Company & It’s concerned details are stored in

Database Table — Company

Step [11] – Relationship between Company_id & Customer_id stored in

Database table –> company_advanced_customer_entity

Step [12] – Company Credit related details stored in

Database Table–>company_credit

Step [13] – Company payment related details stored. in

Database Table –> company_credit

Step [14] – Company Roles related details stored in

Database Table–>company_roles

Step [15] – Company Structure related ID details stored in

Database Table–>company_structure

Step [16] – Company negotiable quote related ID details stored in

Database Table –> negotiable_quote_company_config

Step [17] – Company purchase order related details stored in

Database Table –> purchase_order_company_config

Step [18] – Company purchase order related details stored in

Database Table –> purchase_order_company_config

Step [19] — Once Company Account User Logged , It is My Account DashBoard as