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):
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¶
- 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:
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