Изменение дизайна и доработка функционала страницы оформления заказа (checkout), Api Нова пошта.

Вибачте цей текст доступний тільки в “Російська”.

Техническое задание.

 

В связи с изменением общего стиля сайта, возникла необходимость в изменении внешнего вида страницы оформлении заказа. Также необходимо доработать функционал на этой странице.

 

Анимация полей как во всплывающих окнах регистрации и входа. Пример функционала можно посмотреть на сайте allo.ua.

 

Скриншоты этапов оформления заказа с сайта allo.ua:

 

скриншот алло новый покупатель
скриншот алло постоянный покупатель
скриншот алло оплата и доставка

 

При оформлении заказа будет две вкладки:

 

1 – Контактные данные.

 

скриншот новый покупатель
скриншот постоянный покупатель

 

Здесь, в свою очередь, должно быть 2 вкладки «Новый клиент» и «Постоянный клиент».

 

Поля для «Новый клиент»:

 

– Имя;

 

– Телефон (Номер телефона по шаблону как при регистрации, с шаблоном и проверкой);

 

– Email;

 

– Город (С этим полем посложнее, так как хотим сделать чтобы можно было выбирать отделения НП со списка);

 

2 – Оплата и доставка.

 

скриншот оплата и доставка
скриншот оплата и доставка моб.

 

При переходе на этот пункт должна появиться кнопка «Промокод», при нажатии на кнопку как и раньше появляется поле с вводом промокода и кнопка, только кнопку сделать черной.

 

Нужно сделать, чтобы в зависимости от города можно было выбрать отделения Новой Почты именно в это городе

 

Переключение между всеми вкладками должно быть без перезагрузки страницы.

 

Делаем:

 

Поле «Город» решено было перенести на вкладку «Оплата и доставка».

 

Интересные моменты:

 

Поле для ввода телефона по маске.

 

<pre><code>
<div class="input-call form-new-input">
    <input class="input-type4" id="tf-chk" name="phone" type="tel" pattern="^\+\d{2}\(\d{3}\)\s\d{3}[-]\d{2}[-]\d

{2}$"  autocomplete="off" value="<?=$customer_phone?>" required>
    <label class="form-new-label">Телефон</label>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/3.3.4/inputmask/inputmask.min.js"></script>

<script>
    var inputsTel = document.querySelectorAll('input[type="tel"]');
    Inputmask({"mask": "+38(999) 999-99-99", showMaskOnHover: false }).mask(inputsTel);
</script>

</code></pre>

 

Интеграция с Api Новой почты.

 

Сделал модуль для ввода адресов Новой почты.

 

Настройка модуля находится в админке : Модули -> Новая почта Api Города и Отделения.

 

В админке настраиваются поля:

 

– Ключ API Новой почты;

 

– Точка входа API Новой почты;

 

– Количество городов в списке.

 

Админка API Новой почты

 

Модуль получает из базы населенных пунктов Новой почты через Api список названий для поля Город при выборе способа доставки.

 

Запрос списка названий происходит после набора 3-х символов в поле Город.

 

После ответа из Api Новой почты под полем появляется список из 5-ти,(настраивается в админке), наиболее подходящих населенных пунктов.

 

Из этого списка клиент должен выбрать нужный.

 

После этого, если выбран пункт “В отделение Новой Почты”, на сервер Новой почты посылается следующий запрос, для получения списка отделений для выбранного населенного пункта.

 

После получения ответа на этот запрос, под полем “Номер отделения НП”, выводится список отделений находящихся в выбранном городе.

 

Если выбран пункт “В отделение Укрпочты” или “Курьером” посылается запрос только для поля Город.

 

Поля формы «Город» и «Номер отделения» и их обработка на стороне клиента:

 


<pre><code>
<input class="input-type4 " id="city-chk" type="text" name="city" autocomplete="off" value = "<?=$logged ? 

$customer_city : ''; ?>" required > 
<label class="form-new-label">Город</label>

<script>
<input class="input-type4" id="shipp-addr-chk" type="text" name="shipping_address" autocomplete="off" value = "" 
required > 
<label id="dost_adr_vidd_np" class="form-new-label"><?=$text_ad?></label>
  $('input[id="city-chk"]').focus(function() {
      if($('input[id="city-chk"]').val().length > 0 ){
        $('input[id="city-chk"]').autocomplete("search", $('input[id="city-chk"]').val()); // Принудительно запускаем 

поиск
      }
  })
    $('input[id="city-chk"]').autocomplete({  //поиск списка городов по api Новой почты
        'source': function(request, response) {
          $.ajax({
            url: 'index.php?route=checkout/cart/autocomplete_city&city=' + request.term ,
            dataType: 'json',
            success: function(json) {
              response($.map(json, function(item) {
                return {
                  value: item['value'],
                  label: item['label'],
                  ref_city: item['ref_city'],
                }
              }));
            }
          });
        },
        'select': function(event, ui) {
          $(this).attr('id_city', ui.item['ref_city'] ); // Установить атрибут id_city поля Город
          $('input[id="shipp-addr-chk"]').val(''); // очистить поле номер отделения Новой почты
        if( $('#np_to_otd').prop('checked'))  {
          $('input[id="shipp-addr-chk"]').autocomplete("search", "i"); // Принудительно запускаем поиск отделений  
        }
        },
        'minLength': 3, // начинать поиск с трех символов
        'delay': 10 //ms
      });

    $('input[id="shipp-addr-chk"]').autocomplete({  //поиск списка отделений по api Новой почты
        'source': function(request, response) {
          $.ajax({
            url: 'index.php?route=checkout/cart/autocomplete_otd&find=' + request.term + '&city_id='+$('#city-
chk').attr('id_city') ,
            dataType: 'json',
            success: function(json) {
              response($.map(json, function(item) {
                return {
                  value: item['value'],
                  label: item['label'],
                  ref_city: item['ref_city'],
                }
              }));
            }
          });
        },
        'select': function(event, ui) {
          //console.log(ui.item['label']);
          $(this).attr('id_city', ui.item['ref_city'] );
        },
        'minLength': 0, // начинать поиск с трех символов
        'delay': 10 //ms
      });
  $('input[id="shipp-addr-chk"]').focus(function() {
    if ( !$('input[id="city-chk"]').attr('id_city') ){
        $('input[id="city-chk"]').focus();  // фокус на поле Город
    }else{
      $('input[id="shipp-addr-chk"]').autocomplete("search", "i"); // Принудительно запускаем поиск отделений  
    }
  });
</script>
</code></pre>

 

Обработка На стороне сервера:

 

<pre><code>
<?php
public function autocomplete_city() { //поиск списка городов по api Новой почты
.....
	$city = $this->request->get['city'];
	$arr_citys = $this->model_extension_module_anapinp->find_citys_by_name($city);
	if($arr_citys){
		foreach ($arr_citys as $city) {
			$json[] = array(
				'label'	=> $city['Present'],
				'value' => $city['MainDescription'],
				'ref_city' => $city['DeliveryCity'],
				);
		}
	}
	$this->response->addHeader('Content-Type: application/json');
	$this->response->setOutput(json_encode($json));
}
public function autocomplete_otd() { //поиск списка отделений по api Новой почты
	$city_id = $this->request->get['city_id'];
	$arr_otds = $this->model_extension_module_anapinp->find_otd_by_citys_id($city_id);
	foreach ($arr_otds as $otd) {
		$json[] = array(
			'label'	=> $otd['Description'],
			'value' => $otd['Description'],
			'ref_city' => $otd['Ref'],
			);
	}
	$this->response->addHeader('Content-Type: application/json');
	$this->response->setOutput(json_encode($json));
}

//Модель

class ModelExtensionModuleanapinp extends Model {
	public function find_citys_by_name($city) { //поиск списка городов по api Новой почты
		$limit = $this->config->get('anapinp_kvo_city');
		$api_key = $this->config->get('anapinp_api_key');
		$novaposhta_api_url = $this->config->get('anapinp_np_api_url');
		$curl = curl_init();
		curl_setopt_array($curl, array(
		CURLOPT_URL => $novaposhta_api_url,
		CURLOPT_RETURNTRANSFER => True,
		CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
		CURLOPT_CUSTOMREQUEST => "POST",
		CURLOPT_POSTFIELDS => "{\r\n\"apiKey\": \"" . $api_key . "\",\r\n\"modelName\": \"Address\",\r\n
\"calledMethod\": \"searchSettlements\",\r\n\"methodProperties\": {\"CityName\": \"" . $city ."\", \"Limit\": \"" . $limit . "\"}\r\n}",
		CURLOPT_HTTPHEADER => array("content-type: application/json",),
		));
		$response = json_decode(curl_exec($curl), TRUE);
		$err = curl_error($curl);
		curl_close($curl);
		if ($err) {
			return false;
		}else{
			return $response['data'][0]['Addresses'];
		}
	}

	public function find_otd_by_citys_id($city_id) { //поиск списка отделений по api Новой почты
		$api_key = $this->config->get('anapinp_api_key');
		$novaposhta_api_url = $this->config->get('anapinp_np_api_url');
	   	$curl = curl_init();
		curl_setopt_array($curl, array(
		CURLOPT_URL => $novaposhta_api_url,
		CURLOPT_RETURNTRANSFER => True,
		CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
		CURLOPT_CUSTOMREQUEST => "POST",
		CURLOPT_POSTFIELDS => "{\r\n\"apiKey\": \"" . $api_key . "\",\r\n\"modelName\": \"Address\",\r\n
\"calledMethod\": \"getWarehouses\",\r\n\"methodProperties\": {\"CityRef\": \"" . $city_id ."\"}\r\n}",
		CURLOPT_HTTPHEADER => array("content-type: application/json",),
		));
		$response = json_decode(curl_exec($curl), TRUE);
		$err = curl_error($curl);
		curl_close($curl);
		if ($err) {
			return false;
		}else{
			return $response['data'];
		}
	}
}
?>
</code></pre>

 

Вот что получилось :

 

Поле город модуль Api Новой почты
Поле номер отделения модуль Api Новой почты

 

И в целом:

 

Новый дизайн Контактные данные
Новый дизайн поле Оплата и доставка

 

Заказчик остался доволен.