diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
index 9005e4816b43f..083c594996d59 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
@@ -1,7 +1,7 @@
@@ -12,7 +12,11 @@
-
,
+
+
+ ,
+
+
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
index c5cc997d8cc85..f760fd0eb8e67 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
@@ -1,7 +1,7 @@
@@ -11,7 +11,10 @@
-
,
+
+ ,
+
+
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
index 292edbc13708c..c803d7950f5ee 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
@@ -1,7 +1,7 @@
@@ -11,7 +11,10 @@
- ,
+
+ ,
+
+
diff --git a/app/code/Magento/Customer/Block/Widget/City.php b/app/code/Magento/Customer/Block/Widget/City.php
new file mode 100644
index 0000000000000..e64485cda5faf
--- /dev/null
+++ b/app/code/Magento/Customer/Block/Widget/City.php
@@ -0,0 +1,182 @@
+options = $options;
+ parent::__construct($context, $addressHelper, $customerMetadata, $data);
+ $this->addressMetadata = $addressMetadata;
+ $this->_isScopePrivate = true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function _construct()
+ {
+ parent::_construct();
+
+ // default city location
+ $this->setTemplate('Magento_Customer::widget/city.phtml');
+ }
+
+ /**
+ * Can show prefix
+ *
+ * @return bool
+ */
+ public function showCity()
+ {
+ return $this->isAttributeVisible(self::ATTRIBUTE_CODE);
+ }
+
+ /**
+ * Retrieve customer attribute instance
+ *
+ * @param string $attributeCode
+ *
+ * @return AttributeMetadataInterface|null
+ * @throws LocalizedException
+ */
+ //@codingStandardsIgnoreStart
+ protected function _getAttribute($attributeCode)
+ {
+ //@codingStandardsIgnoreEnd
+ if ($this->getForceUseCustomerAttributes() || $this->getObject() instanceof CustomerInterface) {
+ return parent::_getAttribute($attributeCode);
+ }
+
+ try {
+ $attribute = $this->addressMetadata->getAttributeMetadata($attributeCode);
+ } catch (NoSuchEntityException $e) {
+ return null;
+ }
+
+ if ($this->getForceUseCustomerRequiredAttributes() && $attribute && !$attribute->isRequired()) {
+ $customerAttribute = parent::_getAttribute($attributeCode);
+ if ($customerAttribute && $customerAttribute->isRequired()) {
+ $attribute = $customerAttribute;
+ }
+ }
+
+ return $attribute;
+ }
+
+ /**
+ * Retrieve store attribute label
+ *
+ * @param string $attributeCode
+ *
+ * @return string
+ */
+ public function getStoreLabel(string $attributeCode)
+ {
+ $attribute = $this->_getAttribute($attributeCode);
+ return $attribute ? __($attribute->getStoreLabel()) : '';
+ }
+
+ /**
+ * Get string with frontend validation classes for attribute
+ *
+ * @param string $attributeCode
+ *
+ * @return string
+ * @throws LocalizedException
+ */
+ public function getAttributeValidationClass(string $attributeCode)
+ {
+ return $this->_addressHelper->getAttributeValidationClass($attributeCode);
+ }
+
+ /**
+ * Checks is attribute visible
+ *
+ * @param string $attributeCode
+ *
+ * @return bool
+ */
+ private function isAttributeVisible(string $attributeCode)
+ {
+ $attributeMetadata = $this->_getAttribute($attributeCode);
+ return $attributeMetadata ? (bool)$attributeMetadata->isVisible() : false;
+ }
+
+ /**
+ * Check if city attribute enabled in system
+ *
+ * @return bool
+ */
+ public function isEnabled()
+ {
+ return $this->_getAttribute(self::ATTRIBUTE_CODE)
+ ? (bool)$this->_getAttribute(self::ATTRIBUTE_CODE)->isVisible() : false;
+ }
+
+ /**
+ * Check if city attribute marked as required
+ *
+ * @return bool
+ */
+ public function isRequired(): bool
+ {
+ return $this->_getAttribute(self::ATTRIBUTE_CODE)
+ ? (bool)$this->_getAttribute(self::ATTRIBUTE_CODE)->isRequired() : false;
+ }
+}
diff --git a/app/code/Magento/Customer/Model/Address/Validator/General.php b/app/code/Magento/Customer/Model/Address/Validator/General.php
index 23c6d687328f3..3329fa490383d 100644
--- a/app/code/Magento/Customer/Model/Address/Validator/General.php
+++ b/app/code/Magento/Customer/Model/Address/Validator/General.php
@@ -1,7 +1,7 @@
'street']);
}
- if (!ValidatorChain::is($address->getCity(), NotEmpty::class)) {
- $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'city']);
- }
-
return $errors;
}
@@ -88,6 +84,8 @@ private function checkRequiredFields(AbstractAddress $address)
* @param AbstractAddress $address
* @return array
* @throws LocalizedException|ValidateException
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
*/
private function checkOptionalFields(AbstractAddress $address)
{
@@ -111,6 +109,12 @@ private function checkOptionalFields(AbstractAddress $address)
$errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'company']);
}
+ if ($this->isCityRequired()
+ && !ValidatorChain::is($address->getCity(), NotEmpty::class)
+ ) {
+ $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'city']);
+ }
+
$havingOptionalZip = $this->directoryData->getCountriesWithOptionalZip();
if (!in_array($address->getCountryId(), $havingOptionalZip)
&& !ValidatorChain::is($address->getPostcode(), NotEmpty::class)
@@ -154,6 +158,17 @@ private function isFaxRequired()
return $this->eavConfig->getAttribute('customer_address', 'fax')->getIsRequired();
}
+ /**
+ * Check if city field required in configuration.
+ *
+ * @return bool
+ * @throws LocalizedException
+ */
+ private function isCityRequired()
+ {
+ return $this->eavConfig->getAttribute('customer_address', 'city')->getIsRequired();
+ }
+
/**
* Reload address attributes for the certain store
*
diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerShowCityActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerShowCityActionGroup.xml
new file mode 100644
index 0000000000000..03d9c9cabcc3a
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerShowCityActionGroup.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ Goes to the customer configuration. Set "Show City" with provided value.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AdminCustomerConfigData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AdminCustomerConfigData.xml
index 47b37a4a8e264..8a9690a88c86f 100644
--- a/app/code/Magento/Customer/Test/Mftf/Data/AdminCustomerConfigData.xml
+++ b/app/code/Magento/Customer/Test/Mftf/Data/AdminCustomerConfigData.xml
@@ -18,6 +18,11 @@
Optional
Required
+
+ No
+ Optional
+ Required
+
No
Optional
diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigData.xml
index 3eb14604220e9..ba3c8ee0a9757 100644
--- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigData.xml
+++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigData.xml
@@ -1,8 +1,8 @@
diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml
index 671bdde86432f..92fe75714d49b 100644
--- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml
+++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerConfigSection.xml
@@ -1,8 +1,8 @@
@@ -17,6 +17,7 @@
+
diff --git a/app/code/Magento/Customer/etc/adminhtml/system.xml b/app/code/Magento/Customer/etc/adminhtml/system.xml
index ec76e09fdf459..8ae8641d3d099 100644
--- a/app/code/Magento/Customer/etc/adminhtml/system.xml
+++ b/app/code/Magento/Customer/etc/adminhtml/system.xml
@@ -1,8 +1,8 @@
@@ -266,6 +266,11 @@
Magento\Config\Model\Config\Source\Nooptreq
Magento\Customer\Model\Config\Backend\Show\AddressOnly
+
+
+ Magento\Config\Model\Config\Source\Nooptreq
+ Magento\Customer\Model\Config\Backend\Show\AddressOnly
+
diff --git a/app/code/Magento/Customer/etc/config.xml b/app/code/Magento/Customer/etc/config.xml
index 23a7c9ebb4034..46ac5921e3d10 100644
--- a/app/code/Magento/Customer/etc/config.xml
+++ b/app/code/Magento/Customer/etc/config.xml
@@ -1,8 +1,8 @@
@@ -59,6 +59,7 @@
req
opt
+ req
0
@@ -71,7 +72,7 @@
{{depend street2}}{{var street2}}{{/depend}}
{{depend street3}}{{var street3}}{{/depend}}
{{depend street4}}{{var street4}}{{/depend}}
-{{if city}}{{var city}}, {{/if}}{{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
+{{depend city}}{{var city}},{{/depend}} {{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
{{var country}}
{{depend telephone}}T: {{var telephone}}{{/depend}}
{{depend fax}}F: {{var fax}}{{/depend}}
@@ -83,7 +84,7 @@
{{depend street2}}{{var street2}}
{{/depend}}
{{depend street3}}{{var street3}}
{{/depend}}
{{depend street4}}{{var street4}}
{{/depend}}
-{{if city}}{{var city}}, {{/if}}{{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
+{{depend city}}{{var city}},{{/depend}} {{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
{{var country}}
{{depend telephone}}T: {{var telephone}}{{/depend}}
{{depend fax}}
F: {{var fax}}{{/depend}}
@@ -94,7 +95,7 @@
{{depend street2}}{{var street2}}|{{/depend}}
{{depend street3}}{{var street3}}|{{/depend}}
{{depend street4}}{{var street4}}|{{/depend}}
-{{if city}}{{var city}}, {{/if}}{{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}|
+{{depend city}}{{var city}},|{{/depend}} {{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}|
{{var country}}|
{{depend telephone}}T: {{var telephone}}|{{/depend}}
{{depend fax}}F: {{var fax}}|{{/depend}}|
diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml
index 517d8151b5f10..a634425abdf32 100644
--- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml
+++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml
@@ -1,8 +1,8 @@
-
-
-
-
-
-
+ getLayout()->createBlock(City::class) ?>
+ isEnabled()): ?>
+ = $_city->setCity($formData->getCity())->toHtml() ?>
+