Appearance
Shipping, Reporting, and Administration
This page maps the legacy Symfony menu entries for shipping, reports, operational tools, and system administration to their source actions. Evidence is the reviewed axelites/logidav source at commit 88d9180215a5d489407498fe4905fdd38efd756d; it is not deployed-runtime or owner-acceptance evidence.
Access and route conventions
The menu builder filters menu children against the user's menu-access list and lets ROLE_ADMIN bypass that menu filter. Individual controllers often call mz.menu_provider->hasAccess() as well. Menu visibility does not establish the authorization behavior of every supporting AJAX route or of the new application reached through a redirect.
The route names below are the stable source identifiers. Controller prefixes include idf, up-stairs, edi, erp/asirgroup, sale, and v2; method annotations supply the route suffix and any {id} or {source} constraint. Menu v2_index links pass a redirect_to query value to the bridge described at the end of this page.
Shipping operations
| Menu group | Routes | Source-backed workflow |
|---|---|---|
| IDF: Commandes, Retour / échange, Planning, Livraison IDF, Rapport de livraison, Envoi vers IDF | idf_index, idf_exchange_or_return, idf_planning, idf_delivery, idf_delivery_report, idf_scan | IdfController renders order, exchange/return, planning, delivery, and scan screens over sales and sale products. The order/return/planning rows include a no-stock action wired to POST /sale/sale-update-product-stock; SaleProductService::setSaleProductAsNoStock() marks the line no-stock, clears printed/container state, resets the sale's CSV-printed flag, and logs the change. The order rows also emit real-shipping and sale-status edit controls, but the IDF index template does not define the sale_update_real_shipment, sale_status_update, or realShipment globals required by sales.js, so those edits are not source-verified as usable from this screen. Appointment and planning controls are described below. The delivery report defaults to the last seven days and accepts a date range, customer, and postcode. The scan view decodes QR input, checks the sale/products, and keeps the selected order/product IDs in Symfony session state. Its two confirmation actions are detailed below. A page load or QR response alone does not prove a delivery occurred. |
| Monté à l'étage: Commandes, Planning, Livraison à l'étage | up_stairs_index, up_stairs_planning, up_stairs_delivery | GET /up-stairs/ and GET /up-stairs/up-stairs-planning check the corresponding menu access keys and render the order and planning tables; GET /up-stairs/up-stairs-delivery checks its menu access key and opens the separate scan/lookup screen. The paginators query SaleService::searchUpStairsTransporter() and searchUpStairsPlanning() over Sale/SaleProduct; planning loads UP_STAIRS_TRANSPORTER users. The row action POST /sale/sale-update-product-up-stairs rejects missing, shipped, or already-upstairs products before SaleService::setIsUpStairs() sets the line flag/date and logs it. Both order and planning tables also expose the shared no-stock action. Planning lets the user assign selected rows, view a transporter calendar, and edit appointments. Its delivery-form link and transporter assignment wiring have source mismatches detailed below. |
| Monté à l'étage avec montage: FDP par catégorie / par produit | up_stairs_extra_shipping_amount, up_stairs_extra_shipping_by_product | Category and product screens filter by category and expose numeric extra-shipping values. Their POST update actions persist Category or Product, write a user-attributed log, and enqueue a CategoryDataUpdateProcessor; Menzzo products also enqueue ProductDataUpdateProcessor. Queueing an update does not prove that Magento received or accepted it. |
| EDI Teliway | edi_ticket_generation_index | Although the menu label says Teliway, the legacy controller calls this the ASIR ticket page and lists AsirPackingService rows with campaign, pallet/box, SKU, quantity, weights, packing date, and a stored-file link. The inspected page action does not itself prove a Teliway exchange or carrier delivery confirmation. |
| AsirGroup → Livraison | sale_asir_group_livraison | AsirGroupMenzzoShippingLabelController renders the barcode and parcel workflow. Supporting QR, label, pallet, truck, and shipment routes use SaleProduct, SaleProductShipment, SaleProductShippingLabel, AsirPallet, pallet-product links, and truck services. These actions can record scans and shipping/pallet state and generate/print labels. Carrier acceptance or delivered status must be checked at the carrier boundary; it is not proven by a Logidav response. |
| VIR → Produits Menzzo | menzzo_products_to_vir_expedition | ProductController lists Menzzo products through searchMenzzoProductToVirExpedition(); the paginated table can be filtered/exported and lets the user select products across pages. The confirmation POST /product/menzzo-products-to-ship-with-vir-tag (menzzo_products_to_ship_with_vir_tag) sets mz_product.to_ship_with = vir and queues ProductDataUpdateProcessor with the VIR-bas-immeuble custom attribute. The UI displays the handler response and clears the selection; this is local tagging plus queued synchronization, not proof that Magento accepted the update. The separate VIR delivery log is a new-Logidav target below. |
| Truck contents, EDI information, printed but undelivered orders | v2_index?redirect_to=app.trucks_content, app.edi_information, app.scanned_but_unshipped_sales | These menu links cross to the new application. Only their target names and the Symfony bridge are verified here; target filters, mutations, and authorization are not in the supplied source. |
| VIR delivery log | v2_index?redirect_to=app.vir_delivery_log | New-application target; its behavior is unverified in this source packet. |
Shipping configuration values are business data. The source shows category/product values being saved locally and queued for downstream product-data synchronization, but it does not establish the consumer run, remote acceptance, or storefront value. The AsirGroup route set is much larger than its one menu entry; use the controller's route names and underlying shipment/pallet services when diagnosing a specific scan or label action.
The IDF order and exchange/return screens prefill appointment state with idf_called, then post the selected sale-product IDs, call result, failure reason or appointment date/time window, and comment to POST /idf/fix-appointment. Success updates call status, appointment fields, tracking identifiers/links, and dispatches a registered SaleProductsIdfAppointmentFixedEvent; its listener sends a confirmation email for Menzzo-source sales. Failure stores the reason/comment and clears appointment times. Both branches write a SaleLog; a saved appointment is not delivery confirmation. From Planning, POST /idf/idf-transporter-masse assigns the selected product lines to the chosen IDF_TRANSPORTER user; transporter_calendar reads that transporter's scheduled orders. POST /idf/update-appointment changes the time window for unshipped IDF products on a sale, while POST /idf/update-idf-planning clears call and appointment fields for called products and logs the cancellation. idf_planning_print produces a PDF for selected order IDs. sale_cancel_product_idf clears IDF state and transporter/appointment fields only when the selected product is currently assigned to IDF and not shipped; shipped or non-IDF lines are not canceled by that action.
On the IDF scan screen, POST /sale/sale-qrcode-check_scan (sale_qrcode_check_for_scan_page) records a SaleProductScan and sale log for each found scanned product and returns warnings for changed, canceled, already-shipped, or non-processing orders; the UI asks for confirmation before adding a warned scan to the session selection. sendToIdf posts each selected sale-product ID to POST /sale/sale-update-product-idf (sale_update_product_idf), which rejects missing rows, Temu orders, and shipped/already-IDF products before calling the sale service to set the IDF state. deliveryToDay and deliveryTomorrow instead post the encoded selected sales to POST /idf/notify_customers; that handler starts menzzo:delivery:send:notification, which selects the configured today/tomorrow SMS text and calls the customer notification service for email and SMS. The UI polls a token for command output. These are distinct actions: an accepted request or completed local command log does not prove carrier delivery or message-provider delivery.
The upstairs order list uses POST /up-stairs/fix-appointment for its call result, optional failure reason/comment, and successful date/time window. A successful call stores the selected appointment; a failed call stores the reason and comment and stamps current date/time fields, rather than clearing the appointment fields as the IDF failure branch does. The action updates selected SaleProduct call fields and writes a SaleLog; POST /up-stairs/up-stairs-called reloads the first selected line's prior call details (KO when it is not marked called). POST /up-stairs/update-appointment accepts a sale ID and date/time window, then changes all unshipped, upstairs lines on that sale and logs the change. Unlike the IDF appointment action described above, this upstairs action contains no event dispatch; a confirmation email is not established by it. Cancellation uses POST /up-stairs/sale-cancel-product-up-stairs; missing input returns KO, while shipped or non-upstairs lines return no body, and eligible lines have their upstairs flag, created date, call fields, appointment, and transporter cleared before a user-attributed SaleLog is written.
The planning view assigns users from the UP_STAIRS_TRANSPORTER list, but its bundled assignment JavaScript calls POST /idf/idf-transporter-masse, not the dedicated POST /up-stairs/up-stairs-transporter-masse. Both handlers set SaleProduct.transporter; the IDF endpoint's success log says the product was sent to IDF. The dedicated upstairs endpoint has the same request fields (sale_product, compte) and writes that IDF wording too, but the inspected planning template does not call it. Therefore source shows the assignment UI path and the handler behavior, but not an upstairs-specific assignment action from that view. The planning template also reads selected-row state from orders_upstairs_not_printed_* cookies in its table redraw, while its selection, assignment, and clear handlers use orders_idf_not_printed*; persisted selection can therefore be inconsistent, and the cross-page effect is not verified. The calendar calls GET /up-stairs/transporter-calendar with transporter id and start/end bounds; it delegates to SaleService::calendarByTransporter() with type upStairs and returns JSON. The two assignment handlers return KO when the product ID is absent; broader route authorization is not established by these methods. Also, the planning paginator builds its delivery-form link with only the sale id, while the route named up-stairs-sale-sketchpad requires both numeric {id} and {spIds}; generated-link behavior is unresolved from source inspection.
The upstairs order and planning templates both load sales.js, define sale_update_product_stock, and render the .send-no-stock control. After confirmation the script posts a productId-saleProductId value to POST /sale/sale-update-product-stock; the controller extracts the sale-product ID and calls SaleProductService::setSaleProductAsNoStock(). That service copies current product availability to the line, sets isSentInStock=0 and isSentNoStock=1, clears print/container fields, resets Sale.isCsvPrinted, and writes a sale log; the non-mass endpoint returns OK, while missing input returns KO. The controller's getIsSentInStock() || true condition is always true, so no further “sent in stock” guard prevents this local update. This action changes Logidav state; it does not show a warehouse receipt.
The separate delivery screen decodes a QR code or resolves a typed tracking code with get_tracking_code_content, then posts the decoded sale ID and product IDs to POST /up-stairs/qrcode-up-stairs. A found sale returns a generated URL to GET /up-stairs/sketchpad/{id}/{spIds}; an unknown sale returns status: KO. The sketchpad route requires a numeric sale ID and includes only selected, non-canceled products that are upstairs or are eligible return/exchange lines; it excludes ordinary previously shipped lines and lines already recorded as upstairs-delivered in a SaleLog. If no products survive, it throws MessageException("Commande déjà livré", 400). The page accepts checked product IDs, a signature image/JSON, comment, an absence flag, and optional image proof files. These routes do not contain an explicit hasAccess() call in the inspected actions; whether a firewall or other access layer protects them was not checked.
Submitting POST /up-stairs/sketchpad/{id}/pdf with not_here=1 increments Sale.noPresentation, clears call/appointment/transporter fields for eligible selected upstairs lines, stores an optional comment, and logs non-presentation with proof links when uploads succeeded. Proof uploads are stored under the web/pdf_idf/{incrementId} path even though the delivery document is stored under web/pdf_up_stairs/{incrementId}. For a delivery, SaleService::createOrderShipment() calls the configured Magento sale API with selected order-item IDs, quantities, and IDF tracking values. The controller then tests if ($resultat || true), so the local path continues even after a false result or caught API exception: it creates the delivery PDF and marks selected lines shipped/printed with carrier ETAGE_IDF, transporter, timestamps, sale delivery fields, logs and shipment events, and updates sale completion. A truthy API result is copied to the line's shipment ID; it is not required for those local updates. PDF, proof upload, and email failures are logged/notified in their respective catch paths. Consequently, local shipped state, generated paperwork, and an email attempt do not prove Magento accepted the shipment or the customer received it.
The same PDF action handles SAV return/exchange lines. Return products are locally moved from idfReturn=1 to 2; exchange lines are moved to idfExchange=3 after the return document path. For a returned line, a missing linked SaleSav or an invalid required refund amount produces a JSON error. The return flag is saved before linked-SAV and amount validation, so an error response does not prove the local flag was rolled back. When the SAV final action is accepted, SaleSavService::createPreRefundBySav() creates and links a Refund row with authorization enabled/status 0 if one does not already exist, then completes the SAV; TEST-tagged SAVs skip that operation. This is pre-refund preparation in Logidav, not a provider refund request or settlement. The amount validator requires a positive numeric value with at most two decimal places. Exchange/return paperwork and local state transitions do not prove that a replacement shipment or money movement completed.
Reports
| Report family | Menu route names | Data path and limits |
|---|---|---|
| Expéditions facturées / Commandes modifiées | invoiced_shipments, orders_updated | ReportController reads a date filter for invoiced shipments and calls the sale repository shipping report. The modified-orders page renders a report view; its AJAX/pagination action supplies the result list. These reports summarize records and do not mutate an order. |
| Ventes / Ventes Dropship / Ventes V2 | sale_list_sku_stat, sale_list_sku_stat_dropship, sale_list_sku_stat_v2 | SaleController accepts date range/day, product label, manufacturer, and subcategory filters. It combines sale-product SKU aggregates with sale aggregates. The dropship version uses supplier configuration and a dropship-specific repository query; the V2 screen has its own template and access key. |
| Disponibilité des produits / Ventes-Disponibilités | product_statistic, sale_statistic | StatisticController calls StatisticService for availability and sale-availability intervals; AJAX endpoints refresh the tables and charts. These are aggregates, not an inventory adjustment path. |
| Stats des ventes | stat_vente_statistic | Uses SalesPerformancePeriodFactory and sale-repository aggregates for fixed short, weekly, and yesterday windows, including comparison variants. It is distinct from the new-application Ventes V2 report. |
| Traductions | stat_trans_index | TransController loads active products and renders the translation statistics view. The page action is a read path; edit behavior is outside this menu route. |
| SAV par produit / agent / fabricant | sav_product_index, sav_agent_stat, sav_manufacture_stat | SaleSavController renders SAV statistics and paginates through corresponding repository queries. These are case aggregates, not refund or stock-return confirmation. |
| Historique des messages SAV / Stats des messages SAV | sav_log_chat_ai, sav_stat_chat_ai | Reads ChatAiLog records via ChatAiLogService; history returns stored request/result/user/time fields and stats filter by user and date. The same AI endpoint sends the submitted message to OpenAi::openaiCompletion() and stores the text; retention/redaction policy is not established by this snapshot. |
| AsirGroup reports | erp_asirgroup_sale_summary_report, asir_group_invoices_report, asir_group_price_report, log_scan_asir_index | The summary page paginates sale-repository results using the dropship:AsirGroup type and can export the result set. Invoice and price pages are rendered by SystemAlertController; their shared paginator calls SystemAlertService for invoice-report alert rows, with optional sale-product and price-report filters, and reads import-file records for invoice details. The scan-log page uses LogScanAsirService. These are local report/import records, not proof that an invoice was accepted by AsirGroup. |
| New-application Ventes V2 | v2_index?redirect_to=app.sales.report | The menu target is named in Builder.php; the report itself is outside the supplied legacy source. |
Divers and operational tools
| Menu group | Routes | What is established by the source |
|---|---|---|
| Mapping / Voxpay | mapping_index, voxpay_index | The mapping route renders its page. Voxpay renders a page and has a POST action that returns a phone-store link containing encoded date, current-user email, and Voxpay-token data. Treat generated links as sensitive; the page action does not prove that a phone-store transaction completed. |
| Reviews → Menzzo.fr | show_all_reviews_action?source=menzzo.fr | Requires both the reviews parent and Menzzo Website menu access, then reads review rows through ReviewsService and its repository. This is a database-backed list; no fresh review-provider synchronization is shown in the page action. |
| Chat history, Trustpilot excluded products, Trustpilot notified-client log | v2_index?redirect_to=app.chat-history.index, app.excluded_products, app.trustpilot_log | These are new-application targets. Only the target names and bridge are verified here. |
| Synchronisation | divers | SaleController accepts an order increment ID, asks the configured Magento API service for sales_order.info, then updates Sale.status and records a SaleLog when a status is returned. A failed lookup returns KO; a local update is not proof that another system consumed it. |
| Export des commandes Menzzo | divers_export | The page defaults to today, statuses processing, complete, and canceled_processing, stores 3 and 4, source Menzzo, and excludes legacy columns. Its POST validates submitted status/store/source choices and launches menzzo:sale:export with a polling token. The menu action can create an export artifact; this page does not establish downstream import or acceptance. |
| Logs | product_price_logs, refund_log, divers_prod_stock_log, divers_cmd_log, divers_sav_log, log_divers_export, log_divers_messages, log_divers_mails_retard, container_log_index, new_product_log_index | These controllers render log/list views backed by their corresponding product, refund, sale, SAV, export, message, container, or new-product log services/repositories. Most tables use column search/sort/pagination and some expose export formats. A log entry establishes that a local event was recorded; it is not itself proof that the external provider or carrier accepted the event. |
| Imported/exported CSV and print files | divers_view_csv, divers_view_csv_export, divers_view_pdf, divers_rdv_retrait_pdf | The CSV views scan web/csv_import/ and web/csv_export/; the invoice-PDF view scans web/pdf_invoices/. These views default to files dated today. The RDV retrait PDF route is handled by SaleRdvController. File presence is local evidence only; it does not prove that a file was transmitted or printed. |
| Product photos / cron list / system alerts / queues | product_photo_index, cron_job_index, system_alert_index, queue_index | These are product-photo, cron-record, system-alert, and queue views. The cron list is not proof of the host scheduler's installed schedule or last successful execution. The system-alert page lists model-authorized alerts for non-admin users and exposes selected-row reimport and resolve actions through POST /system-alert/fix-alert (system_alert_fixer). Reimport skips ineligible alerts or alerts without an order increment ID, calls the sale importer, and resolves only alerts whose order appears in its result; resolve directly stamps resolved_by/resolved_at. The queue list does not prove a worker consumed or completed a message. |
| Marketing and wishlists | beyable_listing, wishlist_listing, wishlist_products_statistiqes | The Beyable route renders its listing screen; its deeper data/provider behavior is not established from that action. Wishlist list accepts optional productId and queries the wishlist repository for customer, email, product, and treated/mail-sent state. The statistics screen uses a separate repository aggregate. Provider sync and mutation behavior are not inferred from these page actions. |
| Wholesale leads | v2_index?redirect_to=app.contact_leads | New-application target; the target's lead fields and workflow are not in the supplied source. |
| AI Commandes | sale_fix_processing_log_index | Opens the sale-fix processing-log view. The menu target and log screen do not prove a repair was applied to an order. |
| Trésorerie → Tableau / Saisie | v2_index?redirect_to=treasury.index, treasury.entry | New-application targets; balances, entry constraints, and persistence behavior are not verified here. |
Système and administrative access
| Menu entry | Route | Source-backed boundary |
|---|---|---|
| Gestion de comptes | user_index | UserController loads the user list and main menu choices. The route calls the menu access service; specific account mutations belong to their separate POST actions. |
| Liste des e-mails | mails_list | ProductController reads the stored mail records and renders the list. The inspected page action does not send an email. |
| Notifications → Groupes | v2_index?redirect_to=app.notification_groups | New-application target; its CRUD and delivery effects are unverified. |
| Config livraison boutiques | v2_index?redirect_to=app.delivery_store_config | New-application target; its store rules and downstream synchronization are unverified. |
| Paramètres | config_index | ConfigController reads the mz.config collection and runs a configuration consistency helper before rendering. The page GET is not evidence of a changed downstream configuration. |
| Microsoft OAuth | v2_index?redirect_to=app.microsoft.oauth.index | New-application target; provider setup and callback behavior are unverified. |
| Log d'accès / Log d'actions | user_access_index, user_activity_index | Renders access and activity history. UserAccessLogController declares /{id} with a numeric constraint while the menu builds user_access_index without an ID; route generation/matching for that menu link is therefore unresolved from source alone. These are audit views, not proof that a denied request was blocked at every route. |
| Tools → Export fixture commande | technical_tools_order_fixture_export | Menu child is only added for ROLE_ADMIN or ACCESS_ORDER_FIXTURE_EXPORT; the controller repeats that check and throws access denied otherwise. The export route is an explicit fixture-generation tool, not a production-order workflow. |
Symfony-to-new-Logidav bridge and remaining gaps
For v2_index, V2Controller serializes the current user ID, request IP, user agent, action time, and redirect_to, saves a LaravelLoginToken through LaravelLoginTokenService, then redirects to the configured new-Logidav authentication endpoint. The configured URL and any token are intentionally not reproduced here. This verifies the legacy bridge code only; it does not verify the destination route, target authorization, page behavior, or whether the redirect succeeds in a deployed environment.
New-application targets in this menu scope are app.sav.archived_test, app.vir_delivery_log, app.trucks_content, app.edi_information, app.scanned_but_unshipped_sales, app.sales.report, app.chat-history.index, app.excluded_products, app.trustpilot_log, app.contact_leads, treasury.index, treasury.entry, app.notification_groups, app.delivery_store_config, and app.microsoft.oauth.index. Their page behavior is not represented as source-verified on this legacy-only packet.
Source paths are pinned to the reviewed commit in source_refs. system_alert_index declares GET /system-alert/{id} and user_access_index declares GET /user-access-log/{id}, both with a required numeric {id}, while their menu entries supply no ID; route generation/matching is unresolved from this snapshot. The alert-fix action itself contains no hasAccess() call in the inspected controller method; broader firewall authorization was not checked. No production host, database, browser, deployed service, or application runtime was inspected. Shipment/carrier acceptance, customer-message delivery, queue consumption, report correctness on live data, and new-application behavior remain unverified.