Skip to main content

SaleProductAvailabilityService Documentation

Overview​

The SaleProductAvailabilityService is a custom service designed to determine product availability and delivery information for sale products. This service handles the complex logic where the "dispo" (availability date) can come from two different sources:

  1. Container arrival date: When a container is assigned to a product
  2. Product availability date: The product's inherent availability field

This service is based on the original Magento logic and adapted for the Symfony/Doctrine environment.

Location​

  • Service File: src/AppBundle/Services/SaleProductAvailabilityService.php
  • Test File: tests/Services/SaleProductAvailabilityServiceTest.php
  • Service Registration: src/AppBundle/Resources/config/services.yml

Service Registration​

The service is registered as mz.saleproductavailability in the services configuration:

mz.saleproductavailability:
class: "%mz.saleproductavailability.class%"
autowire: true
calls:
- [ setEntityManager, [ "@doctrine.orm.entity_manager" ] ]

Key Concepts​

Dispo (Availability Date)​

The "dispo" represents when a product will be available. It can come from multiple sources, checked in this priority order:

  1. Container Assignment (Highest Priority): If a SaleProduct has a container assigned, the container's arrivalAt date is used as the dispo
  2. Sale Product's Dispo Client Date: The dispoClientDate field from the SaleProduct entity
  3. Sale Product's Available Field: The available field from the SaleProduct entity
  4. Sale Product's Availability Field (Lowest Priority): The availability field from the SaleProduct entity

Important: The service uses the SaleProduct's own availability fields, NOT the base Product entity's fields.

Delivery Window Calculation​

The service calculates delivery date ranges based on:

  • Whether the product is in stock (dispo < current date)
  • The store ID (some stores have different delivery windows)
  • The reference date (either current date or the dispo date)

Standard Delivery Windows:

  • In stock: 2-9 days from reference date
  • Out of stock: 2-9 days from dispo date

Special Store Delivery Windows (Store IDs 29, 19):

  • In stock: 10-17 days from current date
  • Out of stock: 10-17 days from dispo date

Usage Examples​

1. Injecting the Service​

// In a controller
$availabilityService = $this->get('mz.saleproductavailability');

// In a service with dependency injection
use AppBundle\Services\SaleProductAvailabilityService;

class MyService
{
private $availabilityService;

public function __construct(SaleProductAvailabilityService $availabilityService)
{
$this->availabilityService = $availabilityService;
}
}

2. Getting Product Availability Date (Dispo)​

use AppBundle\Entity\SaleProduct;

// Get a sale product
$saleProduct = $saleProductRepository->find($id);

// Get the dispo (availability date in Ymd format)
$dispo = $availabilityService->getProductDispo($saleProduct);
// Returns: '20251115' or null if not available

Logic (checked in priority order):

  1. If the sale product has a container: Returns the container's arrivalAt date
  2. If dispoClientDate is set: Returns the dispoClientDate in Ymd format
  3. If available field is set: Returns the available value
  4. If availability field is set: Returns the availability value
  5. Otherwise: Returns null

Note: The service uses the SaleProduct's own availability fields (dispoClientDate, available, availability), NOT the base Product entity's fields.

3. Checking if Product is In Stock​

// Check if product is currently in stock
$isInStock = $availabilityService->isInStock($saleProduct);
// Returns: true if dispo < current date, false otherwise

4. Getting Delivery Information​

// Get delivery information string
$deliveryInfo = $availabilityService->getOrderDeliveryInfo($saleProduct);
// Returns: "Livraison entre le 15 et le 22 novembre"

5. Getting Calculated Availability Bracket​

// Get availability information with bracket
$availability = $availabilityService->getCalculatedAvailability($saleProduct);

// Returns array:
// [
// 'dispo' => '20251115',
// 'date' => '2_semaines' // Could be: En_Stock, 1_semaines, ..., 16_semaines, >_16_semaines
// ]

Possible date values:

  • En_Stock: Product is in stock (dispo < today)
  • 1_semaines to 16_semaines: Product available within 1-16 weeks
  • >_16_semaines: Product available in more than 16 weeks
  • Fin de produit: End of product lifecycle

6. Custom Delivery Information with Phrase​

// Get delivery info with custom formatting
$customPhrase = 'Livraison entre le %s et le %s';
$deliveryInfo = $availabilityService->getDeliveryInfo(
$dispo = '20251120',
$customPhrase,
$isInStock = false,
$saleProduct = null
);
// Returns: "Livraison entre le 22/11 et le 29/11"

7. Getting Container Information​

// Get container details if product is assigned to a container
$containerInfo = $availabilityService->getContainerInfo($saleProduct);

// Returns array if container exists:
// [
// 'reference' => 'CONT-001',
// 'status' => 'shipped',
// 'arrival_at' => DateTime object,
// 'arrived_at' => DateTime object or null,
// 'ship_name' => 'Test Ship'
// ]

// Returns null if no container assigned

Complete Example: Display Product Availability​

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;

class ProductAvailabilityController extends Controller
{
public function getAvailabilityAction($saleProductId)
{
// Get the sale product
$saleProduct = $this->getDoctrine()
->getRepository('AppBundle:SaleProduct')
->find($saleProductId);

if (!$saleProduct) {
return new JsonResponse(['error' => 'Sale product not found'], 404);
}

// Get the availability service
$availabilityService = $this->get('mz.saleproductavailability');

// Get all availability information
$dispo = $availabilityService->getProductDispo($saleProduct);
$isInStock = $availabilityService->isInStock($saleProduct);
$deliveryInfo = $availabilityService->getOrderDeliveryInfo($saleProduct);
$calculatedAvailability = $availabilityService->getCalculatedAvailability($saleProduct);
$containerInfo = $availabilityService->getContainerInfo($saleProduct);

return new JsonResponse([
'dispo' => $dispo,
'is_in_stock' => $isInStock,
'delivery_info' => $deliveryInfo,
'availability_bracket' => $calculatedAvailability['date'],
'container' => $containerInfo,
]);
}
}

Example Response:

{
"dispo": "20251115",
"is_in_stock": false,
"delivery_info": "Livraison entre le 17 et le 24 novembre",
"availability_bracket": "2_semaines",
"container": {
"reference": "CONT-001",
"status": "shipped",
"arrival_at": "2025-11-15T00:00:00+00:00",
"arrived_at": null,
"ship_name": "MV Ocean Star"
}
}

API Methods Reference​

getProductDispo(SaleProduct $saleProduct): ?string​

Returns the availability date (dispo) for a sale product.

Priority order:

  1. Container's arrivalAt date (if container is assigned)
  2. SaleProduct's dispoClientDate field
  3. SaleProduct's available field
  4. SaleProduct's availability field

Returns: Date in Ymd format (e.g., '20251115') or null


getOrderDeliveryInfo(SaleProduct $saleProduct): string​

Returns delivery information message for a sale product.

Parameters:

  • $saleProduct: The sale product

Returns: Formatted delivery message (e.g., "Livraison entre le 15 et le 22 novembre"). The delivery window defaults to the sale's creation timestamp when available and otherwise uses the current date.


getDeliveryInfo(?string $dispo, ?string $customPhrase, bool $isInStock, ?SaleProduct $saleProduct, ?DateTime $referenceDate = null): string​

Calculate detailed delivery date information.

Parameters:

  • $dispo: Availability date in Ymd format
  • $customPhrase: Custom formatting phrase (e.g., "Livraison entre le %s et le %s")
  • $isInStock: Whether product is in stock
  • $saleProduct: Sale product for additional context (store-specific delivery times)
  • $referenceDate: Optional reference date to anchor the delivery window when the product is already in stock (defaults to "now")

Returns: Formatted delivery information


isInStock(SaleProduct $saleProduct): bool​

Check if a sale product is currently in stock.

Returns: true if in stock, false otherwise


getCalculatedAvailability(SaleProduct $saleProduct): array​

Get availability bracket information.

Returns: Array with:

  • dispo: Raw availability value
  • date: Availability bracket (e.g., 'En_Stock', '2_semaines', etc.)

getContainerInfo(SaleProduct $saleProduct): ?array​

Get container information if product is assigned to a container.

Returns: Container details array or null

Differences from Magento Implementation​

  1. Container Integration: Uses Doctrine ORM relationships instead of Magento's entity system
  2. Service Registration: Uses Symfony's dependency injection instead of Magento's service locator
  3. Month Localization: Currently hardcoded to French month names (can be extended with Symfony's translator)
  4. Store-specific Logic: Simplified to check store ID directly from sale
  5. Availability Source: Uses SaleProduct's own availability fields (dispoClientDate, available, availability) instead of the base Product entity

Future Enhancements​

  1. Localization: Add support for multiple languages using Symfony's translator
  2. Configuration: Move delivery day ranges to configuration files
  3. Event System: Dispatch events when availability changes
  4. Caching: Add caching layer for frequently accessed availability data
  5. Store Configuration: Move store-specific delivery times to database configuration

Testing​

Run the test suite:

vendor/bin/phpunit tests/Services/SaleProductAvailabilityServiceTest.php

The test suite covers:

  • Dispo calculation with and without containers
  • In-stock detection
  • Delivery info formatting
  • Availability brackets
  • Container information retrieval
  • Store-specific delivery windows
  • SaleProduct: /home/user/logidav/src/AppBundle/Entity/SaleProduct.php
  • Product: /home/user/logidav/src/AppBundle/Entity/Product.php
  • Container: /home/user/logidav/src/AppBundle/Entity/Container.php
  • Sale: /home/user/logidav/src/AppBundle/Entity/Sale.php

Support​

For questions or issues with this service, please refer to:

  • The test suite for usage examples
  • The Magento migration notes for original implementation details
  • The service source code for detailed inline documentation