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:
- Container arrival date: When a container is assigned to a product
- 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:
- Container Assignment (Highest Priority): If a
SaleProducthas a container assigned, the container'sarrivalAtdate is used as the dispo - Sale Product's Dispo Client Date: The
dispoClientDatefield from theSaleProductentity - Sale Product's Available Field: The
availablefield from theSaleProductentity - Sale Product's Availability Field (Lowest Priority): The
availabilityfield from theSaleProductentity
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):
- If the sale product has a container: Returns the container's
arrivalAtdate - If
dispoClientDateis set: Returns thedispoClientDatein Ymd format - If
availablefield is set: Returns theavailablevalue - If
availabilityfield is set: Returns theavailabilityvalue - 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_semainesto16_semaines: Product available within 1-16 weeks>_16_semaines: Product available in more than 16 weeksFin 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:
- Container's
arrivalAtdate (if container is assigned) - SaleProduct's
dispoClientDatefield - SaleProduct's
availablefield - SaleProduct's
availabilityfield
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 valuedate: 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β
- Container Integration: Uses Doctrine ORM relationships instead of Magento's entity system
- Service Registration: Uses Symfony's dependency injection instead of Magento's service locator
- Month Localization: Currently hardcoded to French month names (can be extended with Symfony's translator)
- Store-specific Logic: Simplified to check store ID directly from sale
- Availability Source: Uses SaleProduct's own availability fields (
dispoClientDate,available,availability) instead of the base Product entity
Future Enhancementsβ
- Localization: Add support for multiple languages using Symfony's translator
- Configuration: Move delivery day ranges to configuration files
- Event System: Dispatch events when availability changes
- Caching: Add caching layer for frequently accessed availability data
- 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
Related Entitiesβ
- 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