卸価格で少数第二位まで使用する要件が上がった。
こんにちは!@vVv_kenshi_vVvです!
実装できるか調査
dtb_product_classのprice02に小数点が登録できるのは把握していた。
通過設定を変更
プログラムを調査していると、envの設定を変更すれば登録できるようになる事がわかった。
デフォルト(未定義):ECCUBE_CURRENCY=JPY
ドルへ変更:ECCUBE_CURRENCY=USD
管理画面:商品登録で少数第二位まで登録可能になった。
price01, price02両方ともに影響する。
各所円マークがドルマークへ変更される
price02のみ使用したい
PriceTypeのSCALEで、小数点以下の桁数を制御しているのがわかった。
ProductClassTypeExtensionを作成
app/Customize/Form/Extension/Admin/ProductClassTypeExtension.php
PHP
<?php
/**
* price02へWholesalePriceTypeを適用する
*/
namespace Customize\Form\Extension\Admin;
use Customize\Form\Type\WholesalePriceType;
use Eccube\Form\Type\Admin\ProductClassType;
use Symfony\Component\Form\AbstractTypeExtension;
use Doctrine\ORM\EntityManagerInterface;
use Eccube\Common\EccubeConfig;
use Eccube\Entity\ClassCategory;
use Eccube\Form\DataTransformer;
use Eccube\Form\Type\Master\DeliveryDurationType;
use Eccube\Form\Type\Master\SaleTypeType;
use Eccube\Form\Type\PriceType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class ProductClassTypeExtension extends AbstractTypeExtension
{
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @var EccubeConfig
*/
protected $eccubeConfig;
/**
* ProductClassType constructor.
*
* @param EntityManagerInterface $entityManager
*/
public function __construct(
EntityManagerInterface $entityManager,
EccubeConfig $eccubeConfig
) {
$this->entityManager = $entityManager;
$this->eccubeConfig = $eccubeConfig;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('code', TextType::class, [
'required' => false,
'constraints' => [
new Assert\Length([
'max' => $this->eccubeConfig['eccube_stext_len'],
]),
],
])
->add('stock', NumberType::class, [
'required' => false,
'constraints' => [
new Assert\Regex([
'pattern' => "/^\d+$/u",
'message' => 'form_error.numeric_only',
]),
],
])
->add('stock_unlimited', CheckboxType::class, [
'label' => 'admin.product.stock_unlimited__short',
'value' => '1',
'required' => false,
])
->add('sale_limit', NumberType::class, [
'required' => false,
'constraints' => [
new Assert\Length([
'max' => 10,
]),
new Assert\GreaterThanOrEqual([
'value' => 1,
]),
new Assert\Regex([
'pattern' => "/^\d+$/u",
'message' => 'form_error.numeric_only',
]),
],
])
->add('price01', PriceType::class, [
'required' => false,
])
->add('price02', WholesalePriceType::class, [
])
->add('tax_rate', TextType::class, [
'required' => false,
'constraints' => [
new Assert\Range(['min' => 0, 'max' => 100]),
new Assert\Regex([
'pattern' => "/^\d+(\.\d+)?$/",
'message' => 'form_error.float_only',
]),
],
])
->add('delivery_fee', PriceType::class, [
'required' => false,
])
->add('sale_type', SaleTypeType::class, [
'multiple' => false,
'expanded' => false,
'constraints' => [
new Assert\NotBlank(),
],
])
->add('delivery_duration', DeliveryDurationType::class, [
'required' => false,
'placeholder' => 'common.select__unspecified',
])
->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$form = $event->getForm();
$data = $form->getData();
if (empty($data['stock_unlimited']) && is_null($data['stock'])) {
$form['stock_unlimited']->addError(new FormError(trans('admin.product.product_class_set_stock_quantity')));
}
});
$transformer = new DataTransformer\EntityToIdTransformer($this->entityManager, ClassCategory::class);
$builder
->add($builder->create('ClassCategory1', HiddenType::class)
->addModelTransformer($transformer)
)
->add($builder->create('ClassCategory2', HiddenType::class)
->addModelTransformer($transformer)
);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Eccube\Entity\ProductClass',
]);
}
/**
* {@inheritdoc}
*/
public static function getExtendedTypes(): iterable
{
return [ProductClassType::class];
}
}
PriceTypeをコピーして、SCALEを定数で2に設定したWholesalePriceTypeを作成
ファイルパス:app/Customize/Form/Type/WholesalePriceType.php
PHP
<?php
/**
* 卸価格:price02専用Formクラス
* 小数点第2位まで、登録できるように調整
* 通貨タイプ:デフォルトJPYの場合は、小数点の桁数は0に設定されている
*/
namespace Customize\Form\Type;
use Eccube\Common\EccubeConfig;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Range;
class WholesalePriceType extends AbstractType
{
const SCALE = 2;
/**
* @var EccubeConfig
*/
protected $eccubeConfig;
/**
* @var ContainerInterface
*/
protected $container;
/**
* PriceType constructor.
*
* @param EccubeConfig $eccubeConfig
*/
public function __construct(EccubeConfig $eccubeConfig, ContainerInterface $container)
{
$this->eccubeConfig = $eccubeConfig;
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$currency = $this->container->getParameter('currency');
$scale = self::SCALE;
$max = $this->eccubeConfig['eccube_price_max'];
$min = -$max;
$constraints = function (Options $options) use ($max, $min) {
$constraints = [];
// requiredがtrueに指定されている場合, NotBlankを追加
if (isset($options['required']) && true === $options['required']) {
$constraints[] = new NotBlank();
}
if (isset($options['accept_minus']) && true === $options['accept_minus']) {
$constraints[] = new Range([
'min' => $min,
'max' => $max,
]);
} else {
$constraints[] = new Range(['min' => 0, 'max' => $max]);
}
return $constraints;
};
$resolver->setDefaults(
[
'currency' => $currency,
'scale' => $scale,
'grouping' => true,
'constraints' => $constraints,
'accept_minus' => false, // マイナス値を許容するかどうか
]
);
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return MoneyType::class;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'price';
}
}