Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Stock Item configuration #2297

Closed
wants to merge 11 commits into from
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryConfiguration\Model;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\InventoryConfigurationApi\Api\Data\SourceItemConfigurationInterface;
use Magento\InventoryConfigurationApi\Api\GetBackorderStatusConfigurationValueInterface;

class GetBackorderStatusConfigurationValue implements GetBackorderStatusConfigurationValueInterface
{
/**
* @var ResourceConnection;
*/
private $resourceConnection;

/**
* @var ScopeConfigInterface
*/
private $scopeConfig;

public function __construct(
ResourceConnection $resourceConnection,
ScopeConfigInterface $scopeConfig
) {
$this->resourceConnection = $resourceConnection;
$this->scopeConfig = $scopeConfig;
}

/**
* @inheritDoc
*/
public function forSourceItem(string $sku, string $sourceCode): ?int
{
$connection = $this->resourceConnection->getConnection();
$configurationTable = $this->resourceConnection->getTableName('inventory_configuration');
$select = $connection->select()
->from($configurationTable)
->where('sku = ?', $sku)
->where('source_code = ?', $sourceCode)
->where('config_option = ?', SourceItemConfigurationInterface::BACKORDERS);
$data = $connection->fetchRow($select);
if ($data === false || $data['value'] === null) {
return $this->forSource($sourceCode);
}
return (int)$data['value'];
}

/**
* @inheritDoc
*/
public function forSource(string $sourceCode): ?int
{
$connection = $this->resourceConnection->getConnection();
$configurationTable = $this->resourceConnection->getTableName('inventory_configuration');
$select = $connection->select()
->from($configurationTable)
->where('sku IS NULL')
->where('source_code = ?', $sourceCode)
->where('config_option = ?', SourceItemConfigurationInterface::BACKORDERS);
$data = $connection->fetchRow($select);
if ($data === false || $data['value'] === null) {
return $this->forGlobal();
}
return (int)$data['value'];
}

/**
* @inheritDoc
*/
public function forGlobal(): int
{
// FIXME if config value is missing, null casted to int gives 0, that's a different semantic from missing value
return (int)$this->scopeConfig->getValue(
SourceItemConfigurationInterface::XML_PATH_BACKORDERS
);
}

/**
* @inheritDoc
*/
public function execute(string $sku = null, string $sourceCode = null): ?int
{
if ($sku !== null && $sourceCode !== null) {
return $this->forSourceItem($sku, $sourceCode);
}

if ($sourceCode !== null)
{
return $this->forSource($sourceCode);
}

return $this->forGlobal();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryConfiguration\Model;

use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\InventoryConfigurationApi\Api\Data\SourceItemConfigurationInterface;
use Magento\InventoryConfigurationApi\Api\SetBackorderStatusConfigurationValueInterface;

class SetBackorderStatusConfigurationValue implements SetBackorderStatusConfigurationValueInterface
{
/**
* @var ResourceConnection;
*/
private $resourceConnection;

/**
* @var WriterInterface
*/
private $configWriter;

public function __construct(
ResourceConnection $resourceConnection,
WriterInterface $configWriter
) {
$this->resourceConnection = $resourceConnection;
$this->configWriter = $configWriter;
}

/**
* @inheritDoc
*/
public function forSourceItem(string $sku, string $sourceCode, ?int $backorderStatus): void
{
// TODO should validate allowed values?
$connection = $this->resourceConnection->getConnection();
$configurationTable = $this->resourceConnection->getTableName('inventory_configuration');
$select = $connection->select()
->from($configurationTable)
->where('sku = ?', $sku)
->where('source_code = ?', $sourceCode)
->where('config_option = ?', SourceItemConfigurationInterface::BACKORDERS);
$data = $connection->fetchRow($select);
$isNew = false;
if ($data === false) {
$isNew = true;
$data = [
'sku' => $sku,
'source_code' => $sourceCode,
'stock_id' => null,
'config_option' => SourceItemConfigurationInterface::BACKORDERS,
];
}
$data['value'] = $backorderStatus ? (string)$backorderStatus : null;
if ($isNew) {
$connection->insert($configurationTable, $data);
} else {
$where = [
'sku = ?' => $sku,
'source_code = ?' => $sourceCode,
'stock_id IS NULL',
'config_option = ?' => SourceItemConfigurationInterface::BACKORDERS,
];

$connection->update($configurationTable, $data, $where);
}
}

/**
* @inheritDoc
*/
public function forSource(string $sourceCode, ?int $backorderStatus): void
{
// TODO should validate allowed values?
$connection = $this->resourceConnection->getConnection();
$configurationTable = $this->resourceConnection->getTableName('inventory_configuration');
$select = $connection->select()
->from($configurationTable)
->where('sku IS NULL')
->where('source_code = ?', $sourceCode)
->where('stock_id IS NULL')
->where('config_option = ?', SourceItemConfigurationInterface::BACKORDERS);
$data = $connection->fetchRow($select);
$isNew = false;
if ($data === false) {
$isNew = true;
$data = [
'sku' => null,
'source_code' => $sourceCode,
'stock_id' => null,
'config_option' => SourceItemConfigurationInterface::BACKORDERS,
];
}
$data['value'] = $backorderStatus ? (string)$backorderStatus : null;
if ($isNew) {
$connection->insert($configurationTable, $data);
} else {
$where = [
'sku IS NULL',
'source_code = ?' => $sourceCode,
'stock_id IS NULL',
'config_option = ?' => SourceItemConfigurationInterface::BACKORDERS,
];
$connection->update($configurationTable, $data, $where);
}
}

/**
* @inheritDoc
*/
public function forGlobal(int $backorderStatus): void
{
// TODO should validate allowed values?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo validation would save a lot of time in the future

$this->configWriter->save(
SourceItemConfigurationInterface::XML_PATH_BACKORDERS,
$backorderStatus
);
}

/**
* @inheritDoc
*/
public function execute(string $sku = null, string $sourceCode = null, string $backorderStatus = null): void
{
if ($sku !== null && $sourceCode !== null) {
$this->forSourceItem($sku, $sourceCode, is_numeric($backorderStatus) ? (int)$backorderStatus : null);
return;
}

if ($sourceCode !== null)
{
$this->forSource($sourceCode, is_numeric($backorderStatus) ? (int)$backorderStatus : null);
return;
}

if (!is_numeric($backorderStatus)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_numeric might allow values we don't want here (floats, some hex or binary values, larger numbers with powers,
etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it; maybe after introducing validation I can be more specific here

throw new \Magento\Framework\Exception\CouldNotSaveException(
__('Backorder status should be a numeric value to be saved in global scope')
);
}

$this->forGlobal((int)$backorderStatus);
}
}
Loading