Appearance
Stock and Purchasing
This page begins at the active Produits menu in src/AppBundle/Menu/Builder.php, then follows its screens into Symfony annotations, Twig pages, form/AJAX actions, services, and local state. The evidence is the reviewed immutable axelites/logidav source snapshot at 88d9180215a5d489407498fe4905fdd38efd756d. This is a static source map; it does not establish deployed behavior, active permissions, configured schedules, current external-provider responses, or operator acceptance.
The stock menu contains several different quantities and states. Product.qty, inventory quantity, warehouse quantity, ProductInventory rows, incoming CommandProduct/ContainerProduct quantities, and availability dates are maintained through different screens and actions. Treat these as separate data until a traced action connects them.
Menu paths and workflow families
| Active menu group | Menu entries / route families | UI purpose and traced continuation |
|---|---|---|
| Gestion des stocks | product_index, product_prospect_index, product_dropship_stock, end_of_product_stock, product_stock_value_stock_value, product_stock_value_stock_value20210331, product_stock_value_0104202231082023_stock_value, product_stock_value_stock_value20210331_c1204, product_container_stock_value_stock_value20210331, product_calculate_product_stock_value, products_qty_stat_index | Stock table and editable product data; prospects; supplier/dropship stock view; end-of-life product queue; current and named historical stock valuations; quantity statistics. Named historical valuation leaves are separate screens/data snapshots, not a single live-stock total. |
| Achats fournisseurs | product_purchases, product_arrivals, product_arrivals_calendar, product_commands, product_arrival_date_index, product_arrival_reservation_ignore, product_reservations, product_buying_price_index | Purchase and supplier-order tables; container arrivals/calendar; arrival-date follow-up; reservation exclusion/call follow-up; buying-price table. The command/container/unload path is the state-changing purchasing lifecycle below. |
| Les fabricants | manufacturer_index, manufacturer_stock_value_index | Manufacturer maintenance, plus CBM/currency and manufacturer valuation configuration. |
| Gestion des produits | Media library; supplier new-product screens; product catalogue/all/same-SKU/tags/archived; translations; creation stats/synchronization; attributes, price calculation, universe/category tools, decoration images, category positions, EAN and recent-product screens | Product content and catalog administration. Supplier intake families are enumerated below; menu labels sharing a controller still lead to different pages/actions. |
| Emplacements des produits | emplacement, product_orphelin_index | Maintain product location assignments and resolve unassigned/orphan locations. |
| Suivi des quantités vendues | v2_index(redirect_to=app.products_sales_quantity_overview) | Symfony creates a login-token row and redirects to the configured newer Logidav URL. The new application target is outside this source path, so its screen/actions are not asserted. |
| Produits hors stock | sale_list_products_nostock | Product-level shortage report (SKU, availability, order count, quantity), not the out-of-stock order-line queue under Commandes. |
| Inventaire / Inventaire 2 | product_inventory_index, product_inventory_new_index | Emplacement-level inventory rows; second screen adds scanning/print workflow. A separate explicit sync action aggregates unsynced rows into product quantity. |
| Gestion des prix | product_shipping_price_index, product_price_tariff_propose_index, product_price_sheet, product_price_sheet_log, v2_index(redirect_to=app.product_price_update_planning) | Shipping-price grid and update/resync history; tariff proposal and price-sheet calculations/logs; newer price-planning app bridge. |
| Dictionnaires | product_dictionaries_index | SKU dictionary/local-SKU mappings with search/export/update. |
| Gestion des disponibilités | availability_index, availability_all, product_threshold_by_category | Pending and validated availability logs, inline date correction/validation, category threshold maintenance. |
| DropShip | Jolipa, BigBuy, VidaXL, Asir Group, Asir Group Mode, CMP, Notio route families | Supplier catalogue/category/selection and online-product views as available per supplier. See supplier matrix. |
| Merchants | product_merchants_info_index, product_merchants_alert_index, V2 custom labels bridge | Merchant listing and alert screens; custom-label menu route hands off to the newer app. |
| Veille des produits | product_monitoring_index, product_monitoring_report_index | Manage tracked products/URLs and view monitoring report/history. |
| AI | chat_ai | Chat screen; message POST calls the configured OpenAI wrapper and returns generated text. |
Active means the child is not commented out in the pinned menu source. The old product_stock_value route, attribute-management alternative, price V2 menu, dropship-price menu, commented container departure, and several supplier selection leaves are not active menu paths in this snapshot.
Main stock table and location-specific quantities
GET /product/ (product_index) checks stock_product_index, loads manufacturers, attribute sets, any SKU forwarded through the session, and warehouse choices, then renders AppBundle:Product:index.html.twig. GET / POST /product/paginate-product-stock/ reads table filters/order, showNewProducts, and optional SKU, calls ProductRepository::searchProductStock, and returns rows/export. Rows combine SKU/product data, Product.qty, per-warehouse quantities, inventory quantity, arrivals/ordered quantities, stock valuation and latest quantity-log date. Product data and warehouse totals appear together, but use different edit actions.
| Screen control / action | Method and URL | Handler and state effect |
|---|---|---|
| Change product availability | POST /product/update-product-dispo (update_product_dispo), fields id and dispo | ProductController::updateProductDisponibilityAction delegates to ProductService::updateProductDispo. The broader availability/queue contract is in Stock Updates. |
| Edit product quantity | POST /product/update-qty-product (update_qty_product), product ID and quantity fields | Updates core product quantity through the product service and logs the stock change. Negative values are refused unless the user is admin or has CAN_SET_NEGATIVE_QTY. It is not an edit to a single warehouse row. |
| Edit one warehouse quantity | POST /product/update-warehouse-products-qty (update_warehouse_products_qty), product ID, warehouse ID, quantity, comment | Updates the product/warehouse relation through ProductWarehouseService; warehouse quantity history is separately viewable. |
| Move quantity between warehouses | POST /product/move-warehouse-qty (move_warehouse_qty), product ID, from/to warehouse IDs, quantity and comment | Delegates to warehouse quantity move path; it is not equivalent to increasing total product stock. |
| View quantity journals | /product/product-qty-log, /product/product-inventory-qty-log, /warehouse-product-qty-log/warehouse-product-qty-history-by-warehouse | Product, inventory and warehouse histories use separate log screens/actions. They help reconcile which quantity was changed. |
| Product-level shortage view | GET /sale/sale-list-products-nostock (sale_list_products_nostock), then /sale/sale-products-nostock-paginate | SaleController::productsNoStockAction() → Sale/saleProductsNoStock.html.twig; JSON rows show SKU, availability, order count and quantity through ProductRepository::searchProductsNoStock. This is a report, not the Commandes → Expédition → Hors stock queue. |
| Prospects / supplier stock / end-of-life | GET /product-prospect/, /product/dropship-stock, /product/end-of-product-stock and each paginate route | Dedicated ProductProspect/ProductController pages render prospect data/photos, supplier-stock rows, or end-of-product stock. These are separate views; their displayed quantities do not replace the main stock-edit workflow. |
ProductQtyLogService and the linked Stock Updates page document reviewed stock mutation branches and the Magento availability/price queue path. The menu action alone does not show a queue schedule or prove propagation to marketplaces.
Supplier orders, containers, arrivals, and unloading
The Achats screen shows products/manufacturers and in-progress commands through ProductController::productPurchasesAction() and Product:purchases.html.twig. Commandes fournisseurs opens GET /product/commandes (product_commands) → Product:commands.html.twig; its paginated table uses mz.command::searchCommandProduct. Command and command-product rows carry supplier reference, deposit, ordered/shipped quantities, costs and status.
View diagram source
flowchart LR
Purchase["Achats / supplier products"] -->|create or edit command lines| Cmd["Command + CommandProduct"]
Cmd -->|create container| Container["Container + ContainerProduct"]
Container -->|arrivals/calendar and status edits| Arrival["Expected arrival and warehouse"]
Arrival -->|unload-container-store| Stock["Product.qty + inventory qty + ProductWarehouse"]
Stock --> QtyLogs["ProductQtyLog / InventoryQtyLog / ContainerLog"]
Container -->|eligible processing lines| PrintQueue["SaleProduct.toPrint + warehouse"]
InvRows["ProductInventory rows, is_sync=0"] -->|explicit sync command| Stock
The main command/container endpoints are:
| Operator action | Method and URL | Inputs / output / state |
|---|---|---|
| Create supplier command | POST /product/create-command (create_command) | reference, created_at, arrival_at, deposit, products {id, qty, value}, and optional action/id_cmd. CommandProductInputNormalizer rejects invalid line inputs with a flash error/redirect; accepted lines are saved under Command, then the page redirects. |
| View/edit a command | GET /product/command/{id} (product_command_view) | Route-bound Command; renders Product:viewCommand.html.twig with warehouse list. Per-line quantity/value changes use /product/update-cmd-qts or transactional /product/update-cmd-qts-bulk; changes are logged by ContainerLogService. |
| Add products to command | /product/add-product-command (add_product_command) | id_cmd, normalized product IDs, ordered quantities and unit values; redirects to command view. |
| Create container from command lines | /product/create-container (create_container) | cmd_id, selected command-line IDs/quantities, reference, ship name, created/sent/arrival dates, warehouse and transport price. Increments CommandProduct.qtyShipped, creates ContainerProduct rows and marks a command complete when every ordered quantity is covered. |
| Arrivals list / edit | GET /product/arrivals (product_arrivals), GET / POST /product/paginate-product-arrivals; POST /product/update-date-arrival, /product/update-status-container, /product/update-sku-container | Entry requires product_arrivals menu access plus LIST_ARRIVAL or admin for the list. Grid shows container reference, shipment/arrival date, status, warehouse, products, transport and approach fee. Edits save fields and write container logs. |
| Arrival calendar | GET /product/arrivals/calendar; GET /product/paginate-product-arrivals-calendar | Calendar query takes start/end or container_id; returns Container plus ContainerPlanning events. Print controls depend on admin or CAN_PRINT_FROM_INTERFACE_UNLOADING. |
| Print container/product labels | POST /product/etiquettes-container-print; POST /product/print-sale-products-for-container | Container ID and/or warehouse selection produce PDF/print data. Printing is not unloading. |
| Unload container into warehouse | POST /product/unload-container-store | id container and JSON emplacements. Requires a container warehouse; missing warehouse throws an error. If status is already arrived, returns arrived. For lines not matched by its quantity-log heuristic, adds quantities to Product.qty, inventory quantity and an existing matching ProductWarehouse; writes quantity logs, makes eligible processing sale lines printable for that warehouse, applies emplacement assignments and sets container status arrived. |
| Change command/container status | /product/update-status-command, /product/update-status-container | Entity ID and new status; persists and logs transition. These endpoints do not by themselves unload quantities. |
Command, CommandProduct, Container, ContainerProduct, ContainerPlanning, ProductWarehouse and container/quantity logs are the local state boundary. Container creation automatically sets a supplier command complete when its ordered and recorded shipped quantities match. Manual status updates can also set complete, and container-line edits/removals do not reconcile CommandProduct.qtyShipped. Neither the status nor that total is a fulfillment invariant.
Unloading normally sets arrived after its stock changes, but the separate status endpoint can set arrived directly. An already-arrived container returns before warehouse validation or quantity changes; manually assigning that status can therefore bypass unloading.
Retry detection is best-effort: it searches product logs for action Unload, a message containing the container reference, and a quantity delta equal to the individual container line. The loop aggregates duplicate product lines before writing one quantity log and has no enclosing transaction. After a partial failure, the aggregate log may not match an individual line, so a retry can add quantities again. Do not treat the log check as durable per-line idempotency or retry without reconciling container, product, inventory, warehouse and quantity-log state.
The separate Suivi des arrivages leaf (product_arrival_date_index) and buying-price list (product_buying_price_index) are follow-up tables, not additional state transitions in container unloading.
Reservation screens and supplier prices
Reservations ignorées renders Product:arrivalReservationIgnore.html.twig. Paginate returns each product’s SKU/name/image, ignored flag and a status derived from ignore/no-sell state. Inline select POSTs sku and ignore to /product/update-arrival-reservation-ignore. Blank SKU returns HTTP 400; unknown SKU returns HTTP 404; otherwise Product.isIgnoredFromReservation is saved. This setting excludes a product from the reservation path; it does not modify stock quantity.
Réservations de produits renders Product:productReservations.html.twig and uses ProductReservationServiceInterface for its table. /product/product-reservations/{id}/call-info reads call status; POST to the same URL updates call metadata; /email-history reads existing restock-message history. Rows may show mail/SMS/WhatsApp timestamps and errors, but this controller evidence does not prove a notification is delivered or that opening the reservation page sends one.
Prix d’achat des produits (product_buying_price_index) and Achats can edit buying-price/cost-related data. Les fabricants → Gérer les fabricants provides manufacturer management; Gérer les cbm et les devises uses ManufacturerStockValueController/ManufacturerStockValueService for valuation factors. The same menu group includes current and historical valuation reports; date labels (including 31/03/2021 and the 04/22–08/23 interval) describe menu entries and should not be represented as current figures.
Product inventory is not the product-stock table
Inventaire opens GET /product-inventory/ → Product:Inventory/index.html.twig; Inventaire 2 opens /product-inventory/new → Product:Inventory/indexNew.html.twig. Both check the inventory menu permission. The table manages ProductInventory rows keyed to a product and emplacement, with row quantity and is_sync state. Inline row actions call:
| Inventory control | Method and URL | Inputs and effect |
|---|---|---|
| List/search | GET /product-inventory/paginate | Table filters/order; returns inventory/emplacement view and isSync. |
| Add scanned/product quantity | POST /product-inventory/add-new | productId, emplacement, qty, optional force-update flag. Existing product+emplacement row returns a conflict-style prompt unless merge is confirmed; otherwise row is created or quantity accumulated. |
| Edit inventory quantity / emplacement | POST /product-inventory/update-qty; /product-inventory/update-emplacement | Row ID plus new quantity or emplacement ID; modifies inventory-row fields, not core product quantity. |
| Delete inventory row | POST /product-inventory/delete-product-inventory | Inventory row ID; removes that row. |
| Print inventory sheet | POST /product-inventory/print | Token starts menzzo:v2:products:inventory:print; repeated token requests read Block progress. |
| Synchronize inventory into product stock | POST /product-inventory/sync-products-stock | Token starts menzzo:product:inventory:sync-stock; repeated token requests read progress. This is the explicit bridge from inventory rows to core stock. |
SyncStockCommand uses a lock, selects mz_product_inventory rows where is_sync=0, sums quantities by product, calls ProductService::updateProductQty(...), and marks those rows synchronized inside the transaction. It passes updateInMagento=true: for Menzzo products, ProductService calls ProductApi::updateProductStockData before local writes, issuing PUT rest/V1/products/{sku}/stockItems/1. A local transaction rollback does not undo an already accepted external stock update. It catches row-level throwables, rolls back that product’s transaction and records an error in progress/log output. A progress token ending with !END! is the command protocol’s completion marker; this static trace does not prove the command ran successfully in a particular environment.
Availability, thresholds, price, and SKU maintenance
The availability submenu separates unvalidated changes from all/validated history. GET /availability/availability-log/{productId} → Availabilitylog:index.html.twig; GET /availability/paginate-availability-log filters validated=0; POST /availability/availability-update takes productId and date, changes product availability and logs old/new date; POST /availability/mark-as-valid takes selected activity IDs and transactionally marks those log rows validated. GET /availability/availability-log-all and its paginate action show broader history. The separate Seuil du stock par catégorie route (product_threshold_by_category) updates a category threshold; it is not a product availability date.
GET /product/shipping-price/ opens the shipping-price grid, with POST /product/shipping-price/paginate and POST /product/shipping-price/update. Update requires the menu permission, a valid CSRF token and authenticated User; it accepts the edited grid payload, returns HTTP 202 with store/status/bulk UUID records, reports no-op updates separately, and returns HTTP 400 on the service update exception. Resync has GET /resync/candidates and POST /resync; it refuses when the feature is disabled or CSRF/user checks fail and returns queued/skipped/remaining counts. /lookup, /add and /{productId}/history support lookup/manual addition/history. Processing after a bulk UUID is outside this UI action trace.
The Proposition d’offre tarifaire, Base de calcul and Log de calcul des prix routes go through product tariff/price-sheet controller families. Price-sheet rows can be updated/reset/recalculated and logged; their presence is a calculation workflow, not proof a store price has been published. Planification de mise à jour des prix is a v2_index handoff, separate from the legacy price-sheet controller.
The Dictionnaires → SKUs page uses ProductController dictionary routes to list/export mappings and update a local SKU. It is distinct from product identity creation and warehouse stock editing.
Product setup, catalogue, and supplier dropship
Use Product Content and Media for media, category, attribute, universe, decoration and EAN actions; Supplier Catalogues traces intake, selection, review, translation and publication. Pricing and Monitoring expands price calculations, valuations and monitoring.
The menu has a product-content administration branch and a separate supplier dropship branch. The first concerns Logidav product records/content; the second has supplier-specific catalogue/selection/online lists. A menu path in one branch is not evidence that a supplier record was published to every connected store.
| Active menu entries | Source controller family and UI routes | Traced action / state boundary |
|---|---|---|
| Création produit Menzzo, BigBuy, VidaXL, Palimi, Adsteroide, Asir Group, Asir Group Mode, CMP, Notio | new_products_index, new_products_bigbuy_index, new_products_vidaxl_index, new_products_palimi_index, new_products_adsteroide_index, new_products_asir_group_index, new_products_asir_group_mode_index, new_products_cmp_index, new_products_notio_index → NewProductController and supplier controllers | Each menu leaf opens its own supplier intake page; NewProductService and product entities carry candidate rows and processing/status metadata. Supplier pages have distinct selection, creation, description and publication steps. Every supplier field mapping through final Magento/provider acceptance was not traced. |
| Asir Group: Validation de description; Traduction et publication; Notio: Validation de description; Traduction et publication | new_products_to_be_processed_asir_group_index, translation_and_publication_process_asir_group_index; new_products_to_be_processed_notio_index, translation_and_publication_process_index | Dedicated review/translation queues for candidates; do not collapse into the initial intake list. Translation/publication destination acceptance was not verified. |
| Catalogue, Tous les produits, Produits consolidés, tags, archivés, produits nouvellement créés | product_catalog, product_all, product_same_sku_index, product_tags, archived_products_index, product_list_recent_products → ProductController pages and paginate/update endpoints | Reads/filters local product catalog; consolidated/SKU/tags/archive screens use separate predicates/actions. Product status changes and queueing are action-specific; do not infer every catalog screen publishes changes automatically. |
| Mediathèques / Liste des produits | medialibrary_index, medialibrary_product_list | Media-library and product-list routes. Upload, association and deletion actions are mapped in Product Content and Media. |
| Traductions → Produits Menzzo / Produits DropShip / Titres Asir Group | trans_product_index, trans_product_dropship_index, trans_drop_ship_title_index → TransController family | Menzzo route enters TransController::indexAction() and immediately returns a literal “Veuillez traduire dans meduse” exit response; this is a deliberate boundary before a working local page/action. Other translation routes exist, but full downstream publication state is not established here. |
| Statistiques de créations; Synchronization | stat_product_creation_index; synchronize_index | Separate creation-statistics and synchronization pages. The menu alone does not establish import schedule or vendor propagation. See Product Sync for reviewed product-import and queue boundary. |
| Attributes, univers, categories, decoration images | management_attributes_product, calcul_product_price_index, univers_products_index, products_new_categories, product_deco_image, update_product_categories, manage_sync_categories | Attribute/price inputs, universe/category assignment, decoration image operations and category positions are separate edit surfaces. Their individual button contracts are expanded in Product Content and Media and Pricing and Monitoring. |
| EAN management | manage_ean_product, generate_ean, list_ean_by_parcel | Product-level EAN maintenance/generation and parcel EAN listing; external allocation/scan acceptance was not reviewed. |
DropShip submenu matrix:
| Supplier | Active menu leaves and route names | Shared workflow shape / traced boundary |
|---|---|---|
| Jolipa | product_jolipa_index, product_creation_index, product_dropship_online(dropshipName=jolipa) | Product list and product-creation page in ProductController; online list is the parameterized generic dropship view. Product update/creation actions exist in this controller. |
| BigBuy | bigbuy_catalog_category, bigbuy_catalog_index, bigbuy_catalog_selection, bigbuy_index_dicionary, bigbuy_shipping_rates_update_rates_by_csv, bigbuy_dropship_online | BigBuy category/catalog/selection pages plus dictionary, CSV shipping-rate update and online-product table in BigbuyBundle. Selection can add/remove candidates and create supplier-side new-product work; online list uses supplier services/state. |
| VidaXL | vidaxl_category_index, vidaxl_catalogue_index, vidaxl_catalog_selection, vidaxl_dropship_online | VidaXL category/catalog/selection/online screens in VidaxlBundle; selection operations connect catalog candidates to supplier product pipeline. |
| Asir Group | asir_product_management, asir_group_catalogue_index, asir_group_catalog_selection, asir_group_catalog_fast_selection, asir_group_online_products, asir_group_online_products_to_negociate, asir_group_online_products_to_remvoe, asir_group_amazon_products | Asir-specific product management, catalog/selection and distinct online, negotiation, removal and Amazon data views. Online list exposes review/action/visibility workflows; they update Asir product/supplier state and logs. |
| Asir Group Mode | asir_group_mode_catalogue_index, asir_group_mode_catalog_selection, asir_group_mode_online_products, asir_group_mode_catalogue_ai_titles, asir_group_mode_refused_ai_titles | Dedicated bundle routes for catalog/selection/online products and accepted/refused AI-title queues. Title decision endpoints persist title state; AI-title decision is not equivalent to publishing a product. |
| CMP | cmp_category_index, cmp_catalogue_index, cmp_selection_index, cmp_dropship_online | CMP categories/catalog/selection and online-product listing in CmpBundle. |
| Notio | notio_catalogue_index, notio_catalog_selection | Notio catalogue and selection pages; menu snapshot has no Notio online-product leaf. |
These suppliers are distinct entry points but share the high-level candidate → selection → new-product/local product → online-review progression only where their controller code exposes that path. Specific external listing calls, provider responses and all supplier-specific error contracts remain outside this page’s traced boundary. Legacy service wiring is used in this repository; this documentation does not assume Symfony Messenger or universal autowiring.
Emplacements, merchants, monitoring, and AI
Emplacements opens /product/emplacement → Product:emplacement.html.twig; paginate and product-emplacement endpoints maintain hierarchical Emplacement assignments on Product. Produits orphelin opens /product-orphelin/; ProductOrphelinController lists products without a usable emplacement and exposes add/remove/assign/update-quantity actions. These affect product location/orphan state; they do not stand in for ProductInventory row counts.
Merchants pages use MerchantsProductsController: product list, alert list, and filter-state actions. Gestion des libellés personnalisés points to v2_index(redirect_to=app.products.custom_labels), not this controller. V2Controller stores an encoded login token containing user ID, source IP, user agent, action date and redirect target, then redirects to configured new_logidav_url. The target app screens and their authorization/operations were not inspected.
Product monitoring configuration (GET /product/monitoring/) has paginate/search/add-product/add-links/delete-link endpoints and a separate /report page with table/history/status actions. This is a tracked-product/link/report workflow, not stock mutation. Its external monitor execution schedule/result collection is not established by the page routes reviewed here.
AI opens GET /chat-ai/chat-ai → ChatAi/chatAi.html.twig; the page checks chat_ai permission. Its POST /chat-ai/chat-ai-message accepts message, passes it to OpenAi::openaiCompletion with a fixed model identifier and token limit, and returns the text portion as JSON result. The source does not show validation for missing/empty message or a persisted chat-log write in this action; no external request was made during this review.
Trace gaps
The linked product-content, supplier-catalogue, and pricing/monitoring guides trace the principal action contracts for those menu families. Field-by-field supplier validation and every report calculation are not reproduced in this overview. Live supplier publication, reservation notification delivery, installed monitoring schedules/provider responses, and newer-app targets for quantity-sales, price planning and custom labels remain outside the verified boundary.
Other boundaries: entry-page access checks do not prove every AJAX endpoint is separately guarded; no effective user-role matrix was tested; supplier, Magento or monitoring-provider acceptance and installed command schedules were not checked. For reviewed product-import/availability queue behavior, use Product Sync and Stock Updates; for sale-origin stock changes use Sales Import.