diff --git a/Api/Data/CustomFieldsInterface.php b/Api/Data/CustomFieldsInterface.php
index 2324c55..34ee663 100644
--- a/Api/Data/CustomFieldsInterface.php
+++ b/Api/Data/CustomFieldsInterface.php
@@ -26,6 +26,14 @@ interface CustomFieldsInterface
const CHECKOUT_GOODS_MARK = 'checkout_goods_mark';
const CHECKOUT_COMMENT = 'checkout_comment';
+ const ATTRIBUTES = [
+ self::CHECKOUT_BUYER_EMAIL,
+ self::CHECKOUT_BUYER_NAME,
+ self::CHECKOUT_COMMENT,
+ self::CHECKOUT_GOODS_MARK,
+ self::CHECKOUT_PURCHASE_ORDER_NO,
+ ];
+
/**
* Get checkout buyer name
*
@@ -105,4 +113,48 @@ public function setCheckoutGoodsMark(string $checkoutGoodsMark = null);
* @return CustomFieldsInterface
*/
public function setCheckoutComment(string $comment = null);
+
+ /**
+ * Checks if a field is enabled
+ *
+ * @param string $fieldName
+ *
+ * @return bool
+ */
+ public function isFieldEnabled(string $fieldName): bool;
+
+ /**
+ * Checks if buyer name field is enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutBuyerNameEnabled(): bool;
+
+ /**
+ * Checks if buyer name field is enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutBuyerEmailEnabled(): bool;
+
+ /**
+ * Checks if purchase order field is enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutPurchaseOrderNoEnabled(): bool;
+
+ /**
+ * Checks if goods mark field is enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutGoodsMarkEnabled(): bool;
+
+ /**
+ * Checks if comment field is enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutCommentEnabled(): bool;
}
diff --git a/Helper/Config.php b/Helper/Config.php
new file mode 100644
index 0000000..3d38fce
--- /dev/null
+++ b/Helper/Config.php
@@ -0,0 +1,77 @@
+config = $config;
+ $this->storeManager = $storeManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @return array
+ */
+ public function getEnabledFields()
+ {
+ return explode(',',
+ $this->config->getValue('bodak/checkout/enabled_fields',
+ ScopeInterface::SCOPE_STORE));
+ }
+
+ /**
+ * @param $attribute
+ *
+ * @return int
+ */
+ public function getAllowedLength($attribute)
+ {
+ $configPath = 'checkout/general/' . $attribute . '_limit';
+ try {
+ $allowedLength = $this->config->getValue($configPath, ScopeInterface::SCOPE_STORES,
+ $this->storeManager->getStore()->getId());
+ } catch (NoSuchEntityException $e) {
+ $this->logger->error('Cannot get allowed length for custom field. Falling back to default scope value.');
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
+ $allowedLength = $this->config->getValue($configPath);
+ }
+
+ return (int)$allowedLength ?: self::LIMIT_NOT_SET;
+ }
+}
\ No newline at end of file
diff --git a/Model/Checkout/LayoutProcessor/Plugin.php b/Model/Checkout/LayoutProcessor/Plugin.php
new file mode 100644
index 0000000..19e5dae
--- /dev/null
+++ b/Model/Checkout/LayoutProcessor/Plugin.php
@@ -0,0 +1,140 @@
+
+ * @copyright © 2017 Slawomir Bodak
+ * @license See LICENSE file for license details.
+ */
+
+declare(strict_types=1);
+
+namespace Bodak\CheckoutCustomForm\Model\Checkout\LayoutProcessor;
+
+use Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface;
+use Bodak\CheckoutCustomForm\Helper\Config;
+
+class Plugin
+{
+ /**
+ * @var Config
+ */
+ private $config;
+
+ /**
+ * @var array
+ */
+ private $fields = [
+ [
+ 'dataScopeName' => CustomFieldsInterface::CHECKOUT_BUYER_NAME,
+ 'label' => 'Buyer name',
+ ],
+ [
+ 'dataScopeName' => CustomFieldsInterface::CHECKOUT_BUYER_EMAIL,
+ 'label' => 'Buyer email',
+ 'validation' => [
+ 'validate-email' => true,
+ ],
+ 'config' => [
+ 'tooltip' => [
+ 'description' => 'We will send an order confirmation to this email address',
+ ],
+ ],
+ ],
+ [
+ 'dataScopeName' => CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO,
+ 'label' => 'Purchase order no.',
+ ],
+ [
+ 'dataScopeName' => CustomFieldsInterface::CHECKOUT_GOODS_MARK,
+ 'label' => 'Goods mark',
+ ],
+ [
+ 'dataScopeName' => CustomFieldsInterface::CHECKOUT_COMMENT,
+ 'label' => 'Comment',
+ 'config' => [
+ 'cols' => 15,
+ 'rows' => 2,
+ 'maxlength' => null,
+ 'elementTmpl' => 'Bodak_CheckoutCustomForm/form/element/textarea',
+ ],
+ 'showTitle' => false,
+ ],
+ ];
+
+ /**
+ * LayoutProcessor constructor.
+ *
+ * @param Config $config
+ */
+ public function __construct(Config $config)
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $subject
+ * @param array $jsLayout
+ *
+ * @return array
+ * @see \Magento\Checkout\Block\Checkout\LayoutProcessor::process
+ */
+ public function afterProcess(
+ \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
+ array $jsLayout
+ ) {
+ $config = $this->config->getEnabledFields();
+
+ $this->applyLengthLimitToFields();
+
+ foreach ($this->fields as $sortOrder => $field) {
+ if (!in_array($field['dataScopeName'], $config)) {
+ continue;
+ }
+ if (!isset($field['showTitle'])) {
+ $field['showTitle'] = true;
+ }
+
+ $formField = [
+ 'component' => 'Magento_Ui/js/form/element/abstract',
+ 'config' => [
+ 'customScope' => 'customCheckoutForm',
+ 'template' => 'ui/form/field',
+ 'elementTmpl' => 'ui/form/element/input',
+ ],
+ 'provider' => 'checkoutProvider',
+ 'dataScope' => 'customCheckoutForm.' . $field['dataScopeName'],
+ 'label' => $field['showTitle'] ? __($field['label']) : '',
+ 'sortOrder' => $sortOrder + 1,
+ 'validation' => [],
+ ];
+
+ if (isset($field['config'])) {
+ $formField['config'] = array_merge($formField['config'], $field['config']);
+ }
+
+ if (isset($field['validation'])) {
+ $formField['validation'] = array_merge($formField['validation'], $field['validation']);
+ }
+
+ $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']
+ ['children']['shippingAddress']['children']['custom-checkout-form-container']
+ ['children']['custom-checkout-form-fieldset']['children'][$field['dataScopeName']] = $formField;
+ }
+
+ return $jsLayout;
+ }
+
+ private function applyLengthLimitToFields()
+ {
+ foreach ($this->fields as $key => $field) {
+ $fieldName = $field['dataScopeName'];
+ $allowedLength = $this->config->getAllowedLength($fieldName);
+ if ($allowedLength === Config::LIMIT_NOT_SET) {
+ continue;
+ }
+ $this->fields[$key]['config']['maxlength'] = $allowedLength;
+ $this->fields[$key]['validation']['max_text_length'] = $allowedLength;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Model/Config/Source/Option.php b/Model/Config/Source/Option.php
new file mode 100644
index 0000000..a8d4448
--- /dev/null
+++ b/Model/Config/Source/Option.php
@@ -0,0 +1,29 @@
+
+ * @copyright © 2017 Slawomir Bodak
+ * @license See LICENSE file for license details.
+ */
+
+declare(strict_types=1);
+
+namespace Bodak\CheckoutCustomForm\Model\Config\Source;
+
+use \Magento\Framework\Option\ArrayInterface;
+use \Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface;
+
+class Option implements ArrayInterface
+{
+ public function toOptionArray()
+ {
+ return [
+ ['value' => CustomFieldsInterface::CHECKOUT_BUYER_NAME, 'label' => 'Buyer Name'],
+ ['value' => CustomFieldsInterface::CHECKOUT_BUYER_EMAIL, 'label' => 'Buyer email'],
+ ['value' => CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO, 'label' => 'Purchase order no.'],
+ ['value' => CustomFieldsInterface::CHECKOUT_GOODS_MARK, 'label' => 'Goods mark'],
+ ['value' => CustomFieldsInterface::CHECKOUT_COMMENT, 'label' => 'Comment'],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/Model/CustomFields/Validator.php b/Model/CustomFields/Validator.php
new file mode 100644
index 0000000..671eab5
--- /dev/null
+++ b/Model/CustomFields/Validator.php
@@ -0,0 +1,99 @@
+config = $config;
+ $this->underscoreToCamelCase = $underscoreToCamelCase;
+ }
+
+ /**
+ * Returns true if and only if $value meets the validation requirements
+ *
+ * If $value fails validation, then this method returns false, and
+ * getMessages() will return an array of messages that explain why the
+ * validation failed.
+ *
+ * @param mixed $value
+ *
+ * @return boolean
+ * @throws Zend_Validate_Exception If validation of $value is impossible
+ */
+ public function isValid($value)
+ {
+ $valid = true;
+ if (!($value instanceof CustomFieldsInterface)) {
+ throw new Zend_Validate_Exception('Expected value to be instance of \Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface');
+ }
+
+ $this->setValue($value);
+
+ foreach (CustomFieldsInterface::ATTRIBUTES as $attribute) {
+ if (!$this->lengthIsValid($attribute)) {
+ $valid = false;
+ $this->_addMessages([sprintf('Field %s is to long.', $attribute)]);
+ }
+ }
+
+ return $valid;
+ }
+
+ /**
+ * @param $value
+ */
+ private function setValue($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * @param $attribute
+ *
+ * @return bool
+ */
+ private function lengthIsValid($attribute)
+ {
+ $allowedLength = $this->config->getAllowedLength($attribute);
+
+ if ($allowedLength === Config::LIMIT_NOT_SET) {
+ return true;
+ }
+
+ $function = $this->underscoreToCamelCase->filter('get_' . $attribute);
+ $value = call_user_func([$this->value, $function]);
+
+ return mb_strlen($value) <= $allowedLength;
+ }
+}
\ No newline at end of file
diff --git a/Model/CustomFieldsRepository.php b/Model/CustomFieldsRepository.php
index df3763e..649ba05 100644
--- a/Model/CustomFieldsRepository.php
+++ b/Model/CustomFieldsRepository.php
@@ -10,6 +10,8 @@
namespace Bodak\CheckoutCustomForm\Model;
+use Bodak\CheckoutCustomForm\Model\CustomFields\Validator;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\NoSuchEntityException;
@@ -47,31 +49,42 @@ class CustomFieldsRepository implements CustomFieldsRepositoryInterface
*/
protected $customFields;
+ /**
+ * @var Validator
+ */
+ private $validator;
+
/**
* CustomFieldsRepository constructor.
*
* @param CartRepositoryInterface $cartRepository CartRepositoryInterface
- * @param ScopeConfigInterface $scopeConfig ScopeConfigInterface
- * @param CustomFieldsInterface $customFields CustomFieldsInterface
+ * @param ScopeConfigInterface $scopeConfig ScopeConfigInterface
+ * @param CustomFieldsInterface $customFields CustomFieldsInterface
+ * @param Validator $validator
*/
public function __construct(
CartRepositoryInterface $cartRepository,
ScopeConfigInterface $scopeConfig,
- CustomFieldsInterface $customFields
+ CustomFieldsInterface $customFields,
+ Validator $validator
) {
$this->cartRepository = $cartRepository;
$this->scopeConfig = $scopeConfig;
$this->customFields = $customFields;
+ $this->validator = $validator;
}
+
/**
* Save checkout custom fields
*
- * @param int $cartId Cart id
+ * @param int $cartId Cart id
* @param \Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface $customFields Custom fields
*
- * @return \Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface
+ * @return \Bodak\CheckoutCustomForm\Api\Data\CustomFieldsInterface|string
* @throws CouldNotSaveException
* @throws NoSuchEntityException
+ * @throws \Zend_Validate_Exception
+ * @throws LocalizedException
*/
public function saveCustomFields(
int $cartId,
@@ -82,6 +95,10 @@ public function saveCustomFields(
throw new NoSuchEntityException(__('Cart %1 is empty', $cartId));
}
+ if (!$this->validator->isValid($customFields)) {
+ throw new LocalizedException(__('Custom fields contain invalid values.'));
+ }
+
try {
$cart->setData(
CustomFieldsInterface::CHECKOUT_BUYER_NAME,
diff --git a/Model/Data/CustomFields.php b/Model/Data/CustomFields.php
index 377a45c..875dd60 100644
--- a/Model/Data/CustomFields.php
+++ b/Model/Data/CustomFields.php
@@ -21,6 +21,27 @@
*/
class CustomFields extends AbstractExtensibleObject implements CustomFieldsInterface
{
+
+ /**
+ * @var null|array
+ */
+ private $enabledFields = null;
+
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ protected $_scopeConfig;
+
+ /**
+ * AddCustomFieldsToOrder constructor.
+ *
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+ */
+ public function __construct(\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig)
+ {
+ $this->_scopeConfig = $scopeConfig;
+ }
+
/**
* Get checkout buyer name
*
@@ -130,4 +151,60 @@ public function setCheckoutComment(string $comment = null)
{
return $this->setData(self::CHECKOUT_COMMENT, $comment);
}
+
+ /**
+ * @param string $fieldName
+ *
+ * @return bool
+ */
+ public function isFieldEnabled(string $fieldName): bool
+ {
+ if($this->enabledFields === null) {
+ $this->enabledFields = explode(',', $this->_scopeConfig->getValue('bodak/checkout/enabled_fields', \Magento\Store\Model\ScopeInterface::SCOPE_STORE));
+ }
+
+ return in_array($fieldName, $this->enabledFields);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCheckoutBuyerNameEnabled(): bool
+ {
+ return $this->isFieldEnabled(self::CHECKOUT_BUYER_NAME);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCheckoutBuyerEmailEnabled(): bool
+ {
+ return $this->isFieldEnabled(self::CHECKOUT_BUYER_EMAIL);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCheckoutPurchaseOrderNoEnabled(): bool
+ {
+ return $this->isFieldEnabled(self::CHECKOUT_PURCHASE_ORDER_NO);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCheckoutGoodsMarkEnabled(): bool
+ {
+ return $this->isFieldEnabled(self::CHECKOUT_GOODS_MARK);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCheckoutCommentEnabled(): bool
+ {
+ return $this->isFieldEnabled(self::CHECKOUT_COMMENT);
+ }
+
+
}
diff --git a/Observer/AddCustomFieldsToOrder.php b/Observer/AddCustomFieldsToOrder.php
index 5939afa..0c42079 100644
--- a/Observer/AddCustomFieldsToOrder.php
+++ b/Observer/AddCustomFieldsToOrder.php
@@ -22,6 +22,21 @@
*/
class AddCustomFieldsToOrder implements ObserverInterface
{
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ protected $_scopeConfig;
+
+ /**
+ * AddCustomFieldsToOrder constructor.
+ *
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+ */
+ public function __construct(\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig)
+ {
+ $this->_scopeConfig = $scopeConfig;
+ }
+
/**
* Execute observer method.
*
@@ -29,30 +44,42 @@ class AddCustomFieldsToOrder implements ObserverInterface
*
* @return void
*/
- public function execute(Observer $observer)
- {
+ public function execute(
+ Observer $observer
+ ) {
$order = $observer->getEvent()->getOrder();
$quote = $observer->getEvent()->getQuote();
+ $config = explode(',', $this->_scopeConfig->getValue('bodak/checkout/enabled_fields', \Magento\Store\Model\ScopeInterface::SCOPE_STORE));
- $order->setData(
- CustomFieldsInterface::CHECKOUT_BUYER_NAME,
- $quote->getData(CustomFieldsInterface::CHECKOUT_BUYER_NAME)
- );
- $order->setData(
- CustomFieldsInterface::CHECKOUT_BUYER_EMAIL,
- $quote->getData(CustomFieldsInterface::CHECKOUT_BUYER_EMAIL)
- );
- $order->setData(
- CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO,
- $quote->getData(CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO)
- );
- $order->setData(
- CustomFieldsInterface::CHECKOUT_GOODS_MARK,
- $quote->getData(CustomFieldsInterface::CHECKOUT_GOODS_MARK)
- );
- $order->setData(
- CustomFieldsInterface::CHECKOUT_COMMENT,
- $quote->getData(CustomFieldsInterface::CHECKOUT_COMMENT)
- );
+ if (in_array(CustomFieldsInterface::CHECKOUT_BUYER_NAME, $config)) {
+ $order->setData(
+ CustomFieldsInterface::CHECKOUT_BUYER_NAME,
+ $quote->getData(CustomFieldsInterface::CHECKOUT_BUYER_NAME)
+ );
+ }
+ if (in_array(CustomFieldsInterface::CHECKOUT_BUYER_EMAIL, $config)) {
+ $order->setData(
+ CustomFieldsInterface::CHECKOUT_BUYER_EMAIL,
+ $quote->getData(CustomFieldsInterface::CHECKOUT_BUYER_EMAIL)
+ );
+ }
+ if (in_array(CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO, $config)) {
+ $order->setData(
+ CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO,
+ $quote->getData(CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO)
+ );
+ }
+ if (in_array(CustomFieldsInterface::CHECKOUT_GOODS_MARK, $config)) {
+ $order->setData(
+ CustomFieldsInterface::CHECKOUT_GOODS_MARK,
+ $quote->getData(CustomFieldsInterface::CHECKOUT_GOODS_MARK)
+ );
+ }
+ if (in_array(CustomFieldsInterface::CHECKOUT_COMMENT, $config)) {
+ $order->setData(
+ CustomFieldsInterface::CHECKOUT_COMMENT,
+ $quote->getData(CustomFieldsInterface::CHECKOUT_COMMENT)
+ );
+ }
}
}
diff --git a/Observer/Sales/OrderLoadAfter.php b/Observer/Sales/OrderLoadAfter.php
new file mode 100644
index 0000000..2cb9fdb
--- /dev/null
+++ b/Observer/Sales/OrderLoadAfter.php
@@ -0,0 +1,47 @@
+orderExtension = $orderExtension;
+ }
+
+ /**
+ * @param \Magento\Framework\Event\Observer $observer
+ */
+ public function execute(\Magento\Framework\Event\Observer $observer)
+ {
+
+ $order = $observer->getOrder();
+
+ $extensionAttributes = $order->getExtensionAttributes();
+
+ if ($extensionAttributes === null) {
+ $extensionAttributes = $this->orderExtension;
+ }
+
+ $extensionAttributes->setCheckoutBuyerName($order->getData(CustomFieldsInterface::CHECKOUT_BUYER_NAME));
+ $extensionAttributes->setCheckoutBuyerEmail($order->getData(CustomFieldsInterface::CHECKOUT_BUYER_EMAIL));
+ $extensionAttributes->setCheckoutPurchaseOrderNo($order->getData(CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO));
+ $extensionAttributes->setCheckoutGoodsMark($order->getData(CustomFieldsInterface::CHECKOUT_GOODS_MARK));
+ $extensionAttributes->setCheckoutComment($order->getData(CustomFieldsInterface::CHECKOUT_COMMENT));
+
+ $order->setExtensionAttributes($extensionAttributes);
+ }
+}
diff --git a/README.md b/README.md
index 1e1764f..6cea86f 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ Add a custom form fields to Magento 2 checkout. The form will appear in the firs
The form is available for logged in customers and guests. After an order is placed all data are set in `sales_order` table.
Data are still in form after page refreshed, till cart is active.
+It is also possible to enable/disable certain fields per store view in the admin backend.
+
Form data will be set in a `quota` table through independent API request:
- `/V1/carts/mine/set-order-custom-fields` (for logged in customer)
- `/V1/guest-carts/:cartId/set-order-custom-field` (for guest)
diff --git a/composer.json b/composer.json
index 1bb7872..73fa833 100644
--- a/composer.json
+++ b/composer.json
@@ -14,7 +14,11 @@
}
],
"require": {
- "php": "~7.0.0|~7.1.3|~7.2.0"
+ "magento/framework": "^102.0.0|^103.0.0",
+ "magento/module-checkout": "^100.3.0",
+ "magento/module-quote": "^101.1.0",
+ "magento/module-sales": "^102.0.0|^103.0.0",
+ "magento/module-store": "^101.0.0"
},
"autoload": {
"files": [
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
new file mode 100644
index 0000000..ac6f36b
--- /dev/null
+++ b/etc/adminhtml/system.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+ separator-top
+
+ sales
+
+
+
+
+ Bodak\CheckoutCustomForm\Model\Config\Source\Option
+ bodak/checkout/enabled_fields
+
+
+
+ Limit the character length. Leave empty for no limit.
+
+
+
+ Limit the character length. Leave empty for no limit.
+
+
+
+ Limit the character length. Leave empty for no limit.
+
+
+
+ Limit the character length. Leave empty for no limit.
+
+
+
+
+
+
diff --git a/etc/config.xml b/etc/config.xml
new file mode 100644
index 0000000..40e1548
--- /dev/null
+++ b/etc/config.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ checkout_buyer_name,checkout_buyer_email,checkout_purchase_order_no,checkout_goods_mark,checkout_comment
+
+
+
+
\ No newline at end of file
diff --git a/etc/di.xml b/etc/di.xml
index f12ec6a..2c69afe 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -3,4 +3,7 @@
+
+
+
\ No newline at end of file
diff --git a/etc/events.xml b/etc/events.xml
index b6542b3..3c68899 100644
--- a/etc/events.xml
+++ b/etc/events.xml
@@ -3,4 +3,7 @@
+
+
+
\ No newline at end of file
diff --git a/etc/extension_attributes.xml b/etc/extension_attributes.xml
new file mode 100644
index 0000000..307f70f
--- /dev/null
+++ b/etc/extension_attributes.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/i18n/de_DE.csv b/i18n/de_DE.csv
new file mode 100644
index 0000000..b22122d
--- /dev/null
+++ b/i18n/de_DE.csv
@@ -0,0 +1,9 @@
+"Other information","Kundenreferenz"
+"Buyer name","Käufername"
+"Buyer email","Käufer-Emailadresse"
+"Purchase order no.","Bestellnummer"
+"Goods mark","Warenkennzeichnung"
+"Comment","Kommentar"
+"* Required Fields","* Pflichtfelder"
+"Checkout Custom Form Configuration","Checkout Benutzerdefinierte Formular-Konfiguration"
+"Enabled Form Fields","Aktivierte Felder"
\ No newline at end of file
diff --git a/i18n/en_US.csv b/i18n/en_US.csv
index d1356bd..75b55a1 100644
--- a/i18n/en_US.csv
+++ b/i18n/en_US.csv
@@ -4,4 +4,6 @@
"Purchase order no.","Purchase order no."
"Goods mark","Goods mark"
"Comment","Comment"
-"* Required Fields","* Required Fields"
\ No newline at end of file
+"* Required Fields","* Required Fields"
+"Checkout Custom Form Configuration","Checkout Custom Form Configuration"
+"Enabled Form Fields","Enabled Form Fields"
\ No newline at end of file
diff --git a/view/adminhtml/templates/order/view/custom_fields.phtml b/view/adminhtml/templates/order/view/custom_fields.phtml
index b5deef3..ad38599 100644
--- a/view/adminhtml/templates/order/view/custom_fields.phtml
+++ b/view/adminhtml/templates/order/view/custom_fields.phtml
@@ -11,40 +11,50 @@ $customFields = $block->getOrderCustomFields();