OroOrderRecognitionBundle
Important
OroOrderRecognitionBundle is only available in the Enterprise edition.
OroOrderRecognitionBundle adds the AI Smart Order feature to the OroCommerce back-office: it turns a purchase order document (a PDF or an image uploaded through the dashboard widget or received as an email attachment) into a draft order with the pending internal status.
The oro/ai-smart-order package includes two bundles:
OroEntityRecognitionBundle — The generic recognition pipeline built on the ChainProcessor component, the source providers that turn an input into the string sent to the microservice, and the state mapper that records which recognized fields are valid.
OroOrderRecognitionBundle— The order-specific processors, the entity finders, the message queue topics and processors, the email intake, the system configuration, and the back-office UI.
The document recognition itself runs in the AI Smart Order microservice operated by Oro. The microservice is not customizable by integrators and is described in this guide only as an HTTP contract. This guide covers the bundle side: how the recognized data becomes a draft order and where a custom bundle can change that behavior.
Prerequisites
The AI Smart Order feature is enabled in the system configuration, and the microservice URL and API key are set. Both values are automatically configured by the OroCloud team. See Configure Global AI Smart Order Settings.
The connection works. The bundle checks it with a
GET /healthrequest, described in Microservice HTTP Contract.
Important
The oro_order_recognition feature is disabled by Oro\Bundle\OrderRecognitionBundle\Feature\Voter\FeatureVoter while the URL or the API key is empty, even when the feature checkbox is selected.
Architecture Overview
Entry Points
Dashboard widget —
Oro\Bundle\OrderRecognitionBundle\Controller\Dashboard\DashboardController(routeoro_order_recognition_dashboard, ACLoro_order_create) handles the file upload form. Whenenable_async_processingis off, it runs the recognition in the request and returns the URL of the draft order edit page, which the widget opens. When the option is on,Oro\Bundle\OrderRecognitionBundle\Handler\AsyncRecognitionHandlerpersists the uploaded file as anOro\Bundle\AttachmentBundle\Entity\Fileand sends theoro_order_recognition.recognize_order.filemessage.Message queue processors —
FileOrderRecognitionProcessorandEmailAttachmentOrderRecognitionProcessorinOro\Bundle\OrderRecognitionBundle\Async\Processorrun the recognition in a unique job and send websocket and email notifications.System mailbox — The
convert_mailbox_email_to_orderprocess sends theoro_order_recognition.recognize_order.email_attachmentmessage for every non-inline attachment of an email received by a mailbox with theorderprocess type.
The message queue entry points are described in Asynchronous Processing, and the mailbox process in Email Intake.
Recognition Flow
Every entry point calls Oro\Bundle\OrderRecognitionBundle\Manager\OrderRecognizer::recognizeUsing() with the file input and, optionally, the orderOwner and orderCustomerUser inputs. The recognizer runs the get_entity_recognition action of the pipeline:
FileProcessormaps the input (a Symfony file, anEmailAttachment, or aFileentity) to a temporary uploaded file through the file mappers.EntityRecognitionProcessorsends the base64-encoded file content to the microservice and stores therecognized_datapart of the response in the context.OrderProcessorcreates a newOrderwith the PO number, currency, customer notes, thependinginternal status, the ship-until date, the default website, and the owner.OrderRecognitionProcessorattaches a newOrderRecognitionentity to the order.AttachmentProcessorandPreviewFileProcessorattach the source document and the preview image returned by the microservice to the order.CustomerProcessor,CustomerUserProcessor,PaymentTermProcessor,LineItemsProcessor,OrderAddressesProcessor, andShippingMethodProcessormatch the recognized values against existing records through the finders and record the validity of every field in the state mapper.RecognitionDataProcessorstores the raw payload and the recorded state on theOrderRecognitionentity.FinalProcessorcalculates the totals, persists and flushes the order, dispatches theOrderDraftCreatedevent, and sets the order as the pipeline result.
On every flush of an OrderRecognition entity, Oro\Bundle\OrderRecognitionBundle\EventListener\ProgressListener calculates the recognition progress from the recorded state and the field weights. The back-office orders grid shows this progress, and the draft order edit page highlights the fields that require attention.
The processors, their priorities, and the context keys are described in Recognition Pipeline. The finders and the search adapters are described in Customize Entity Matching, and the state mapper and the progress calculation in Recognition State and Progress.
Key Classes
Oro\Bundle\EntityRecognitionBundle\Processor\EntityRecognitionPipeline— The chain processor registered as theoro_entity_recognition.processorservice. It throws a\RuntimeExceptionwhen no processor sets a result.Oro\Bundle\EntityRecognitionBundle\Context\ContextKeysAwareInterface— The constants for the context keys shared by all processors.Oro\Bundle\OrderRecognitionBundle\Manager\OrderRecognizer— The entry point that creates the context and runs the pipeline.Oro\Bundle\OrderRecognitionBundle\Entity\OrderRecognition— The entity linked to the order through therecognitionassociation that the bundle adds toOro\Bundle\OrderBundle\Entity\Order. It stores the raw payload (rawData), the recorded state (mappingData), the line item context (lineItemContext), the progress values (initialProgressandentityProgress), and the preview attachment ID.Oro\Bundle\OrderRecognitionBundle\Connector\OrderRecognitionConnectorandOro\Bundle\OrderRecognitionBundle\Client\OrderRecognitionApiClient— The HTTP layer that sends the recognition request and decodes the response.Oro\Bundle\OrderRecognitionBundle\Finder\FinderInterface— The contract of the finders that match a recognized value against a customer, customer user, product, product unit, region, country, customer address, or payment term.Oro\Bundle\EntityRecognitionBundle\State\StateMapperInterfaceandOro\Bundle\OrderRecognitionBundle\State\StateInterface— The shared state mapper and the per-field state writers.Oro\Bundle\OrderRecognitionBundle\Event\OrderDraftCreated— The event dispatched after the draft order is flushed. See OrderDraftCreated Event.
Draft Order Edit Page
Oro\Bundle\OrderRecognitionBundle\Controller\OrderController provides the draft order edit page at the oro_order_draft_update route (ACL ancestor oro_order_update, template @OroOrderRecognition/Order/draftUpdate.html.twig). The route accepts only an order with the pending internal status and a non-empty recognition association; any other order is redirected to the regular oro_order_update route. The page uses Oro\Bundle\OrderRecognitionBundle\Form\Type\DraftOrderType, a form type whose parent is the standard Oro\Bundle\OrderBundle\Form\Type\OrderType. In finishView(), the form type marks every top-level form field as valid. It then reads OrderRecognition::mappingData and overwrites the data-recognition attribute and the recognition <state> CSS class of every form field, address field, and line item field that has a recorded state. Each line item row also receives the aggregated state of its fields, which is invalid when any field is invalid. The page uses these attributes to highlight the fields whose state is invalid. The oro_order_draft_complete route of the same controller calls Oro\Bundle\OrderRecognitionBundle\Manager\ProgressManagerInterface::markAsComplete() for the top-level mapping data key passed in the request and flushes the order. The Twig functions get_progress_percentage, get_invalid_fields, and is_field_valid_in_order_recognition of Oro\Bundle\OrderRecognitionBundle\Twig\OrderRecognitionExtension read OrderRecognition::entityProgress and Oro\Bundle\OrderRecognitionBundle\Provider\ProgressCalculationProviderInterface for the progress bar and the list of fields that require attention.
Customization Prerequisites
Customizations live in a bundle of the application. All examples in this guide use the
Acme\Bundle\SmartOrderBundlenamespace.A service redefinition or a re-pointed alias takes precedence only when the custom bundle is loaded after OroOrderRecognitionBundle. Set the
priorityof the bundle in itsResources/config/oro/bundles.ymlto a value higher than320, the priority of OroOrderRecognitionBundle.Service decoration with
decorates:does not depend on the bundle load order.Clear the cache after changing service definitions.
A processor can be unit-tested with a plain
Oro\Component\ChainProcessor\Contextpopulated with the keys the processor reads.
Customization Map
Goal |
Extension Point |
Page |
|---|---|---|
Enrich the draft order after it is created |
The |
|
Map an additional payload field |
A custom processor between the priorities |
|
Replace or disable a built-in step |
Service redefinition or decoration of a built-in processor |
|
Change how a customer, product, unit, address, or payment term is matched |
Finder decoration |
|
Change the fallback search |
A custom search adapter |
|
Change the progress weights or the highlighting of fields |
A state writer, the field weight provider, or the progress calculation provider |
|
Accept documents from another source |
A custom message queue topic and processor |
|
Change the mailbox rules |
An override of the |
|
Change the request or normalize the response |
Connector or API client decoration, or a source provider |
|
Hide or show draft orders in the APIs |
The |
Configuration
The bundle configuration root node is oro_order_recognition (Oro\Bundle\OrderRecognitionBundle\DependencyInjection\Configuration). Every option is a system configuration setting, so its full key is oro_order_recognition.<option>. The options are shown under System > Configuration > System Configuration > Integrations > AI Smart Order; enable_entity_recognition and default_currency can also be set per organization.
Option |
Default |
Description |
|---|---|---|
|
|
Enables the AI Smart Order feature. Toggles the |
|
|
The base URL of the AI Smart Order microservice. |
|
|
The API key of the microservice. The value is stored encrypted. |
|
|
Processes files uploaded through the dashboard widget in the message queue instead of the HTTP request. |
|
|
Uses customer part numbers when matching products. Works only with the |
|
|
Hides pending recognized orders from the storefront API and keeps the storefront voter active for storefront API requests. |
|
|
Hides pending recognized orders from the back-office API. |
|
|
The currency of the draft order when the recognized currency is empty or is not a valid ISO code. When empty, the default currency of the organization is used. |
The default values of enable_entity_recognition, order_recognition_url, and order_recognition_api_key are taken from the ORO_AI_ENABLE_ENTITY_RECOGNITION, ORO_AI_ORDER_RECOGNITION_URL, and ORO_AI_ORDER_RECOGNITION_API_KEY environment variables; when a variable is not set, the container falls back to '0', http://127.0.0.1:8000, and an empty string. A value saved in the system configuration takes precedence.
Feature Toggles
The bundle declares two features in Resources/config/oro/features.yml:
oro_order_recognition— Toggled byoro_order_recognition.enable_entity_recognition. It controls theorder_recognitiondashboard widget, theorder_recognitionplaceholder item, theconvert_mailbox_email_to_orderprocess, and theoro_order_mark_as_approvedoperation.FeatureVoteradditionally disables the feature whileorder_recognition_urlororder_recognition_api_keyis empty.oro_order_recognition_cpn— Toggled byoro_order_recognition.use_cpn_in_smart_order. It listsoro_order_recognition_draft_order_cpn_ajaxunderroutesinfeatures.yml. This value is the key of the routing resource that loadsAjaxOrderCpnControllerinResources/config/oro/routing.yml; the controller route itself is namedoro_draft_order_cpn_get_form.Oro\Bundle\OrderRecognitionBundle\Finder\CpnProductFinderDecoratoris always registered and checks the configuration and the availability of the customer part number extension itself whenever the finder it wraps finds no product.
See Feature Toggle for how to check a feature state in custom code.
Draft Orders in the API and Storefront
A recognized order is a regular Order with the pending internal status and a non-empty recognition association. The bundle hides such orders on the storefront and, optionally, in the APIs:
Oro\Bundle\OrderRecognitionBundle\Acl\Voter\OrderFrontendVoteris registered twice inResources/config/services.yml. Theoro_order_recognition.acl.order_voter.frontendinstance denies theVIEWpermission on a pending recognized order on every storefront request, including storefront API requests, for any user. Theoro_order_recognition.acl.order_voter.backofficeinstance applies to back-office requests, but its access check manager,oro_order_recognition.access_check_manager.smart_order_recognized_order.backoffice, starts with the access check disabled and nothing in the bundle enables it. Both instances abstain on orders that are not pending recognized orders, including orders without an internal status.Oro\Bundle\OrderRecognitionBundle\Api\Processor\DisableSmartOrderRecognizedOrderAccessCheckis registered twice inResources/config/services_api.ymlas an API processor in thesecurity_checkgroup of theget,get_list,create,update,delete, anddelete_listactions and of every subresource and relationship action, without aclassrestriction: once for thefrontendrequest type, driven byexclude_draft_orders_from_storefront_api, and once for the!frontendrequest type, driven byexclude_draft_orders_from_backoffice_api. When the option is disabled, the processor disables the access check of the matching voter instance for the request, so the voter abstains.Oro\Bundle\OrderRecognitionBundle\EventListener\Datagrid\OrdersGridConfigListenerexcludes pending recognized orders from thefrontend-orders-griddatagrid. On the back-officeorders-griddatagrid, the same listener adds theentity_progresscolumn, sorter, and filter, and the Edit draft row action that opens theoro_order_draft_updateroute. Both listener methods run only while theoro_order_recognitionfeature is enabled.Oro\Bundle\OrderRecognitionBundle\Api\Processor\ExcludePendingRecognizedOrdersQueryis registered twice inResources/config/services_api.ymlas an API processor for thegetandget_listactions ofOro\Bundle\OrderBundle\Entity\Orderin thebuild_querygroup with priority-120: once for thefrontendrequest type, driven byexclude_draft_orders_from_storefront_api, and once for the!frontendrequest type, driven byexclude_draft_orders_from_backoffice_api. When the option is enabled, the processor adds a condition that excludes orders that are pending and have a recognition. In the back-office API, onlyExcludePendingRecognizedOrdersQueryhides draft orders, and only for thegetandget_listactions.
Logging
All bundle services log to the ai_smart_order Monolog channel declared in Resources/config/oro/app.yml. The channel is written to %kernel.logs_dir%/ai_smart_order_%kernel.environment%.log through a fingers_crossed handler with the info action level, so the file receives the buffered records of a recognition once an info or a higher level record is logged.
The oro_order_recognition.logger service is a public alias of monolog.logger.ai_smart_order. Inject it into a custom processor or finder to keep its records in the same file: