Skip to content

Commit

Permalink
[shopsys] out of stock products behavior (#3587)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitek-rostislav authored Dec 2, 2024
2 parents 4bfc021 + c8d3749 commit ffbba6b
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 128 deletions.
75 changes: 75 additions & 0 deletions src/Form/LuigisBoxCrudExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace Shopsys\ProductFeed\LuigisBoxBundle\Form;

use Shopsys\FrameworkBundle\Component\Domain\AdminDomainTabsFacade;
use Shopsys\FrameworkBundle\Component\Setting\Setting;
use Shopsys\Plugin\PluginCrudExtensionInterface;
use Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting\LuigisBoxFeedSettingEnum;

class LuigisBoxCrudExtension implements PluginCrudExtensionInterface
{
/**
* @param \Shopsys\FrameworkBundle\Component\Setting\Setting $setting
* @param \Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting\LuigisBoxFeedSettingEnum $luigisBoxFeedSettingEnum
* @param \Shopsys\FrameworkBundle\Component\Domain\AdminDomainTabsFacade $adminDomainTabsFacade
*/
public function __construct(
protected readonly Setting $setting,
protected readonly LuigisBoxFeedSettingEnum $luigisBoxFeedSettingEnum,
protected readonly AdminDomainTabsFacade $adminDomainTabsFacade,
) {
}

/**
* {@inheritdoc}
*/
public function getFormTypeClass(): string
{
return LuigisBoxSettingFormType::class;
}

/**
* {@inheritdoc}
*/
public function getFormLabel(): string
{
return t('Luigi\'s Box settings');
}

/**
* {@inheritdoc}
*/
public function getData($id): array
{
$data = [];

foreach ($this->luigisBoxFeedSettingEnum->getAllCases() as $settingName) {
$data[$settingName] = $this->setting->getForDomain($settingName, $this->adminDomainTabsFacade->getSelectedDomainId());
}

return $data;
}

/**
* {@inheritdoc}
*/
public function saveData($id, $data): void
{
foreach ($data as $name => $value) {
$this->setting->setForDomain($name, $value, $this->adminDomainTabsFacade->getSelectedDomainId());
}
}

/**
* {@inheritdoc}
*/
public function removeData($id): void
{
foreach ($this->luigisBoxFeedSettingEnum->getAllCases() as $settingName) {
$this->setting->deleteByName($settingName);
}
}
}
38 changes: 38 additions & 0 deletions src/Form/LuigisBoxSettingFormType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Shopsys\ProductFeed\LuigisBoxBundle\Form;

use Shopsys\FrameworkBundle\Form\MessageType;
use Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting\LuigisBoxFeedSettingEnum;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints;

class LuigisBoxSettingFormType extends AbstractType
{
/**
* @param \Symfony\Component\Form\FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add(LuigisBoxFeedSettingEnum::LUIGIS_BOX_RANK, IntegerType::class, [
'label' => t('Luigi\'s Box rank'),
'required' => true,
'constraints' => [
new Constraints\NotNull([
'message' => 'Please enter the Luigi\'s Box rank.',
]),
new Constraints\Range(['min' => 1, 'max' => 15]),
],
])
->add('luigisBoxRankInfo', MessageType::class, [
'message_level' => MessageType::MESSAGE_LEVEL_INFO,
'data' => t('The value is used for availability_rank setting in Luigi\'s Box feed. See <a href="https://docs.luigisbox.com/indexing/feeds.html">the docs</a> for more information.'),
]);
}
}
37 changes: 37 additions & 0 deletions src/Migrations/Version20241113193905.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Shopsys\ProductFeed\LuigisBoxBundle\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Shopsys\FrameworkBundle\Migrations\MultidomainMigrationTrait;
use Shopsys\MigrationBundle\Component\Doctrine\Migrations\AbstractMigration;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;

class Version20241113193905 extends AbstractMigration implements ContainerAwareInterface
{
use MultidomainMigrationTrait;

/**
* @param \Doctrine\DBAL\Schema\Schema $schema
*/
public function up(Schema $schema): void
{
foreach ($this->getAllDomainIds() as $domainId) {
$this->sql('INSERT INTO setting_values (name, domain_id, value, type) VALUES (:name, :domainId, :value, :type)', [
'domainId' => $domainId,
'name' => 'luigisBoxRank',
'value' => 7,
'type' => 'integer',
]);
}
}

/**
* @param \Doctrine\DBAL\Schema\Schema $schema
*/
public function down(Schema $schema): void
{
}
}
38 changes: 11 additions & 27 deletions src/Model/FeedItem/LuigisBoxProductFeedItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@

class LuigisBoxProductFeedItem implements FeedItemInterface
{
public const UNIQUE_IDENTIFIER_PREFIX = 'product';
protected const SMALL_IMAGE_SIZE = 100;
protected const MEDIUM_IMAGE_SIZE = 200;
protected const LARGE_IMAGE_SIZE = 600;
protected const AVAILABILITY_RANK_OUT_OF_STOCK = 15;
protected const AVAILABILITY_RANK_IN_STOCK = 1;
protected const AVAILABILITY_RANK_AVAILABLE_IN_LONG_TIME = 14;
public const string UNIQUE_IDENTIFIER_PREFIX = 'product';
protected const int SMALL_IMAGE_SIZE = 100;
protected const int MEDIUM_IMAGE_SIZE = 200;
protected const int LARGE_IMAGE_SIZE = 600;
protected const int SELLABLE_PRODUCT_AVAILABILITY = 1;

/**
* @param int $id
* @param string $name
* @param string $catalogNumber
* @param string $availabilityText
* @param bool $isAvailable
* @param int|null $availableInDays
* @param int $availabilityRank
* @param \Shopsys\FrameworkBundle\Model\Pricing\Price $price
* @param \Shopsys\FrameworkBundle\Model\Pricing\Currency\Currency $currency
* @param int $mainCategoryId
Expand All @@ -47,8 +44,7 @@ public function __construct(
protected readonly string $name,
protected readonly string $catalogNumber,
protected readonly string $availabilityText,
protected readonly bool $isAvailable,
protected readonly int|null $availableInDays,
protected readonly int $availabilityRank,
protected readonly Price $price,
protected readonly Currency $currency,
protected readonly int $mainCategoryId,
Expand Down Expand Up @@ -164,27 +160,15 @@ public function getAvailabilityRankText(): string
*/
public function getAvailabilityRank(): int
{
if (!$this->isAvailable) {
return static::AVAILABILITY_RANK_OUT_OF_STOCK;
}

if ($this->availableInDays >= 15 || $this->availableInDays === null) {
return static::AVAILABILITY_RANK_AVAILABLE_IN_LONG_TIME;
}

if ($this->availableInDays <= 0) {
return static::AVAILABILITY_RANK_IN_STOCK;
}

return $this->availableInDays;
return $this->availabilityRank;
}

/**
* @return bool
* @return int
*/
public function getAvailability(): bool
public function getAvailability(): int
{
return $this->isAvailable;
return self::SELLABLE_PRODUCT_AVAILABILITY;
}

/**
Expand Down
21 changes: 16 additions & 5 deletions src/Model/FeedItem/LuigisBoxProductFeedItemFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Shopsys\ProductFeed\LuigisBoxBundle\Model\FeedItem;

use Shopsys\FrameworkBundle\Component\Domain\Config\DomainConfig;
use Shopsys\FrameworkBundle\Component\Setting\Setting;
use Shopsys\FrameworkBundle\Model\Category\CategoryRepository;
use Shopsys\FrameworkBundle\Model\Pricing\Currency\Currency;
use Shopsys\FrameworkBundle\Model\Pricing\Currency\CurrencyFacade;
Expand All @@ -15,6 +16,7 @@
use Shopsys\FrameworkBundle\Model\Product\Pricing\ProductPriceCalculationForCustomerUser;
use Shopsys\FrameworkBundle\Model\Product\Product;
use Shopsys\FrameworkBundle\Model\Product\ProductCachedAttributesFacade;
use Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting\LuigisBoxFeedSettingEnum;

class LuigisBoxProductFeedItemFactory
{
Expand All @@ -25,6 +27,7 @@ class LuigisBoxProductFeedItemFactory
* @param \Shopsys\FrameworkBundle\Model\Category\CategoryRepository $categoryRepository
* @param \Shopsys\FrameworkBundle\Model\Product\ProductCachedAttributesFacade $productCachedAttributesFacade
* @param \Shopsys\FrameworkBundle\Model\Product\Availability\ProductAvailabilityFacade $productAvailabilityFacade
* @param \Shopsys\FrameworkBundle\Component\Setting\Setting $setting
*/
public function __construct(
protected readonly ProductPriceCalculationForCustomerUser $productPriceCalculationForCustomerUser,
Expand All @@ -33,6 +36,7 @@ public function __construct(
protected readonly CategoryRepository $categoryRepository,
protected readonly ProductCachedAttributesFacade $productCachedAttributesFacade,
protected readonly ProductAvailabilityFacade $productAvailabilityFacade,
protected readonly Setting $setting,
) {
}

Expand All @@ -47,8 +51,6 @@ public function create(Product $product, DomainConfig $domainConfig): LuigisBoxP
$rootCategory = $this->categoryRepository->getRootCategory();
$mainCategory = $this->categoryRepository->getProductMainCategoryOnDomain($product, $domainConfig->getId());
$availabilityText = $this->productAvailabilityFacade->getProductAvailabilityInformationByDomainId($product, $domainConfig->getId());
$isAvailable = $this->productAvailabilityFacade->isProductAvailableOnDomainCached($product, $domainConfig->getId());
$availableInDays = $this->productAvailabilityFacade->getProductAvailabilityDaysByDomainId($product, $domainConfig->getId());
$productDescription = $product->isVariant() ? $product->getMainVariant()->getDescriptionAsPlainText($domainConfig->getId()) : $product->getDescriptionAsPlainText($domainConfig->getId());
$categories = $product->getCategoriesIndexedByDomainId()[$domainConfig->getId()];
$categoryHierarchyNamesByCategoryId = [];
Expand Down Expand Up @@ -87,11 +89,10 @@ public function create(Product $product, DomainConfig $domainConfig): LuigisBoxP

return new LuigisBoxProductFeedItem(
$product->getId(),
$product->getName($domainConfig->getLocale()),
$product->getFullName($domainConfig->getLocale()),
$product->getCatnum(),
$availabilityText,
$isAvailable,
$availableInDays,
$this->getAvailabilityRank($product, $domainConfig),
$this->getPrice($product, $domainConfig),
$this->getCurrency($domainConfig),
$mainCategory->getId(),
Expand Down Expand Up @@ -132,4 +133,14 @@ protected function getCurrency(DomainConfig $domainConfig): Currency
{
return $this->currencyFacade->getDomainDefaultCurrencyByDomainId($domainConfig->getId());
}

/**
* @param \Shopsys\FrameworkBundle\Model\Product\Product $product
* @param \Shopsys\FrameworkBundle\Component\Domain\Config\DomainConfig $domainConfig
* @return int
*/
protected function getAvailabilityRank(Product $product, DomainConfig $domainConfig): int
{
return $this->productAvailabilityFacade->isProductAvailableOnDomainCached($product, $domainConfig->getId()) ? 1 : $this->setting->getForDomain(LuigisBoxFeedSettingEnum::LUIGIS_BOX_RANK, $domainConfig->getId());
}
}
20 changes: 20 additions & 0 deletions src/Model/Setting/Exception/LuigisBoxSettingNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting\Exception;

use Exception;

class LuigisBoxSettingNotFoundException extends Exception
{
/**
* @param array $criteria
*/
public function __construct(array $criteria)
{
$message = sprintf('LuigisBoxSetting not found for criteria: %s', json_encode($criteria));

parent::__construct($message);
}
}
12 changes: 12 additions & 0 deletions src/Model/Setting/LuigisBoxFeedSettingEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Shopsys\ProductFeed\LuigisBoxBundle\Model\Setting;

use Shopsys\FrameworkBundle\Component\Enum\AbstractEnum;

class LuigisBoxFeedSettingEnum extends AbstractEnum
{
public const string LUIGIS_BOX_RANK = 'luigisBoxRank';
}
4 changes: 4 additions & 0 deletions src/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ services:
Shopsys\ProductFeed\LuigisBoxBundle\:
resource: '../../*'

Shopsys\ProductFeed\LuigisBoxBundle\Form\LuigisBoxCrudExtension:
tags:
- { name: shopsys.crud_extension, type: stockSettings }

Shopsys\ProductFeed\LuigisBoxBundle\LuigisBoxProductFeed:
tags:
- { name: shopsys.feed, hours: '*', minutes: '15' }
11 changes: 7 additions & 4 deletions src/Resources/translations/messages.cs.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Language: cs\n"

msgid "In stock"
msgstr "Skladem"
msgid "Luigi's Box rank"
msgstr "Luigi's Box rank"

msgid "Out of stock"
msgstr "Vyprodáno"
msgid "Luigi's Box settings"
msgstr "Nastavení Luigi's Box"

msgid "The value is used for availability_rank setting in Luigi's Box feed. See <a href=\"https://docs.luigisbox.com/indexing/feeds.html\">the docs</a> for more information."
msgstr "Hodnota se používá pro nastavení availability_rank v XML feedu pro Luigi's Box. Pro více informací vizte <a href=\"https://docs.luigisbox.com/indexing/feeds.html\">dokumentaci</a>."

7 changes: 5 additions & 2 deletions src/Resources/translations/messages.en.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"

msgid "In stock"
msgid "Luigi's Box rank"
msgstr ""

msgid "Out of stock"
msgid "Luigi's Box settings"
msgstr ""

msgid "The value is used for availability_rank setting in Luigi's Box feed. See <a href=\"https://docs.luigisbox.com/indexing/feeds.html\">the docs</a> for more information."
msgstr ""

9 changes: 9 additions & 0 deletions src/Resources/translations/validators.cs.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: cs\n"

msgid "Please enter the Luigi's Box rank."
msgstr "Zadejte prosím Luigi's Box rank"

9 changes: 9 additions & 0 deletions src/Resources/translations/validators.en.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"

msgid "Please enter the Luigi's Box rank."
msgstr ""

Loading

0 comments on commit ffbba6b

Please sign in to comment.