Over the last few days I have felt an increasing level of frustration as I troubleshoot the attempted development of a new module.
The module has a custom console command which is supposed to generate a cart rule for a 5% discount, applied to the SKU provided as an argument to the command.
I have made a few posts in the magento stackexchange about this and was told, part-way through developing my first solution, that factories are no longer the protocol and that I must use interfaces. So, I re-wrote the command to use interfaces.
I was receiving all kinds of weird and wonderful errors from the server, before I discovered that interfaces do not properly support cart-rule creation yet. So, I then attempted to solve the problem with object manager. Now I can't work out whether or not the code is working because I receive the 'Area code not set' error whenever I attempt to run magento commands with the module installed.
I have attempted every permutation of setting the area code that I have been able to find online nut I still receive the error. Although, as far as all examples I've found of working imply, I should not even need to set the area code on my command.
Code I have so far is as follows:
<?php
/**
* Copyright (c) 2018 Joshua Flood. All rights reserved.
* See COPYING.txt for license details.
*/
namespace [Vendor_name]\[Module_name]\Console\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\Framework\App\Action\Context;
use Magento\Framework\ObjectManagerInterface;
use Magento\SalesRule\Api\RuleRepositoryInterface;
use Magento\SalesRule\Api\Data\ConditionInterface;
/**
* Class WeeklyDiscountCommand
*/
class WeeklyDiscountCommand extends Command
{
/**
* SKU argument
*/
const SKU_ARGUMENT = 'sku';
/**
* @var \Magento\Framework\App\State
*/
protected $appState;
/**
* @var Context
*/
protected $context;
/**
* @var ObjectManagerInterface
*/
protected $_objectManager;
/**
* @var RuleRepositoryInterface
*/
protected $ruleRepository;
/**
* @var ConditionInterface
*/
protected $condition;
public function __construct(
\Magento\Framework\App\State $appState,
Context $context,
ObjectManagerInterface $_objectManager,
RuleRepositoryInterface $ruleRepository,
ConditionInterface $condition
) {
$appState->setAreaCode('admin');
parent::__construct($context);
$this->_objectManager = $_objectManager;
$this->ruleRepository = $ruleRepository;
$this->condition = $condition;
}
public function createRule($sku)
{
$discount = '5';
$salesRule = $this->objectManager->create('Magento\SalesRule\Model\Rule');
$salesRule->setName('JoshuaFlood_DiscountGenerator')
->setDescription('Do not delete! Current product sku - ' .$sku)
->setFromDate(NULL)
->setToDate(NULL)
->setUsesPerCustomer('0')
->setCustomerGroupIds(array('0','1','2','3',))
->setIsActive('1')
->setStopRulesProcessing('0')
->setIsAdvanced('1')
->setProductIds(NULL)
->setSortOrder('1')
->setSimpleAction('by_percent')
->setDiscountAmount($discount)
->setDiscountQty(NULL)
->setDiscountStep('0')
->setSimpleFreeShipping('0')
->setApplyToShipping('0')
->setTimesUsed('0')
->setIsRss('0')
->setWebsiteIds(array('1',))
->setCouponType('1')
->setCouponCode('WEEKLY5')
->setUsesPerCoupon(NULL);
$item_found = $this->objectManager->create('Magento\SalesRule\Model\Rule\Condition\Product\Found')
->setType('Magento\SalesRule\Model\Rule\Condition\Product\Found')
->setValue(1) // 1 == FOUND
->setAggregator('all'); // match ALL conditions
$salesRule->getConditions()->addCondition($item_found);
$conditions = $this->objectManager->create('Magento\SalesRule\Model\Rule\Condition\Product')
->setType('Magento\SalesRule\Model\Rule\Condition\Product')
->setAttribute('sku')
->setOperator('==')
->setValue($sku);
$item_found->addCondition($conditions);
$actions = $this->objectManager->create('Magento\SalesRule\Model\Rule\Condition\Product')
->setType('Magento\SalesRule\Model\Rule\Condition\Product')
->setAttribute('sku')
->setOperator('==')
->setValue($sku);
$salesRule->getActions()->addCondition($actions);
$salesRule->save();
}
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('discountgenerator:weeklydiscount')
->setDescription('Re-assign weekly discount to SKU provided in argument.')
->setDefinition([
new InputArgument(
self:KU_ARGUMENT,
InputArgument::REQUIRED,
'SKU'
),
]);
parent::configure();
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$sku = $input->getArgument(self:KU_ARGUMENT);
if (is_null($sku)) {
throw new \InvalidArgumentException('Argument ' . self:KU_ARGUMENT . ' is missing.');
}
try{
$this->createRule($sku);
} catch(Exception $e) {
echo 'Failed to create rule: ', $e->getMessage(), "\n";
}
$output->writeln('<info>Weekly discount created for product: ' . $sku . '!</info>');
}
}
Too late but I hope it helps someone reusing your code.
One of the issues I see with your code is that admin is not a valid area code. It should be adminhtml instead.
It's always better, and safe, to use constants defined by Magento wherever possible. Like instead of using adminhtml for backend area, we should be using
Magento\Backend\App\Area\FrontNameResolver::AREA_CODE