Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Используем почтовые индексы в своём приложении во благо

Anna | 20.06.2014 | нет комментариев
Я думаю, что на многих сайтах пользователя спросят его физический адрес. Для доставки ли, для отсылки бумажногоспама уведомлений ли. И, в всеобщем-то — это мелочь. Вбил индекс, Москва, область, район, село, улица, дом, квартира. Казалось бы, что здесь упрощать, всякий как бы помнит свой адрес, сложно ли его вбить? Но демон, как неизменно, кроется в мелочах: пользователь опечатывается в адресе, посылка уходит не туда, лучи «добродушна» идут вам в обратную связь и вообще жизнь плохеет.

Приглядитесь к первой части адреса — индексу. В этом комплекте из шести цифр теснее есть область, район и город/село. Их дозволено подставить автоматом. Этим мы убъём сразу 2-х зайцев:

  • Убережём пользователя от ошибок (при вводе неверного индекса он сразу подметит, что город-то не его), что, в случае доставки письма (а то и посылки), может здорово её ускорить (пока её по неверному индексу зашлют, да пока разберутся, что не туда заслали, да отправят туда — пользователь вам всю плешь проест)
  • пользователю будет отрадно, что о нём заботятся :-)

Дело за малым: нам необходима база почтовых индексов.

И она есть! Всамделишняя, электронная и, основное, официальная база индексов от Почты России.

Встречайте: info.russianpost.ru/database/ops.html

База доступна в теснее невиданном для молодых разработчиков формате DBF и регулярно (два раза в месяц) обновляется.

Безусловно, по подробности эта база до ФИАС недотягивает, но, стоит отдать должное, она значительно проще (каждого одна таблица!), следственно, если вам не необходима точность до улицы и дома, а хватит только населённого пункта — вам сюда.

Прикручиваем блаженство к… ну, давайте к сайту.

Выходит, счастливо качаем базу и думаем, как же её впихнуть в применяемый нами КакойТамУНасСовременныйSQL (а то и НеSQL).

Ищем в гугле, ищем в яндексе, ищем в apt-cache, конечный нам счастливо и выдаёт:

envek@envek-work:~$ apt-cache search dbf
pgdbf - converter of XBase / FoxPro tables to PostgreSQL
dbf2mysql - xBase <--> MySQL

Здорово-то как! Я использую Postgres и конвертировать буду в него. В базе применяется ещё досовская кодировка, так что призовём на поддержка iconv. Кстати, самые свежие версии pgdbf (>= 0.6.2) сами шаманством обладают и iconv призывают, но до убунтовского репозитория они ещё не добрались.

mv {PIndx08,post_indices}.dbf # Переименовываем файл, как будет именоваться таблица
pgdbf -u post_indices.dbf | iconv -f CP866 > post_indices.sql # Конвертируем

Что же, сейчас нужно принудить это трудиться.

Я использую Ruby on Rails, на её примере и покажу. Кто рельсы не понимает, может пролистать.

Cоздаём модель, которая будет нашу информацию из базы данных и представлять в приложении

rails g model PostIndex

В миграцию вдумчиво копируем конструкцию таблицы из подлинной базы, делаем индекс первичным ключом:

class CreatePostIndices < ActiveRecord::Migration
  def change
    create_table :post_indices, id: false do |t|
      t.string :index,     limit:  6
      t.string :o ps_name,  limit: 60
      t.string :o ps_type,  limit: 50
      t.string :o ps_subm,  limit:  6
      t.string :region,    limit: 60
      t.string :autonom,   limit: 60
      t.string :area,      limit: 60
      t.string :city,      limit: 60
      t.string :city_1,    limit: 60
      t.date   :act_date
      t.string :index_old, limit:  6
      t.index  :index_old
    end
    reversible do |to|
      to.up do
        execute 'ALTER TABLE post_indices ADD PRIMARY KEY (index);'
      end
    end
  end
end

Слегка настраиваем модель:

class PostIndex < ActiveRecord::Base
  self.primary_key = 'index'
end

Делаем простенький контроллер, тот, что нам почтовый индекс в json-формате отдаст:

# В консоли: rails generate controller PostIndices
class PostIndicesController < ApplicationController
  def get
    @index = PostIndex.where(index: params[:index]).first
    @index = PostIndex.where(index_old: params[:index]).order(:index).first! unless @index
    respond_to do |format|
      format.json { render json: @index.to_json(only: [:index, :region, :area, :city]) }
    end
  end
end

Прописываем в config/routes.rb маршрут, по которому приложение нам отдаст желанные индексы:

get '/post_index/:index(.:format)', controller: :post_indices, action: :get

И, основное: html и javascript, которые и сделают всю магию для пользователя.

HTML-форма:

<form id='address_form'>
  <table>
    <tr>
      <td><label for='address_postcode'>Почтовый индекс</label></td>
      <td>
        <input class='postcode_field' id='address_postcode' name='address[postcode]'>
        <p class='description'>Позже ввода почтового индекса, поля «область», «район» и «город» заполняются механически.</p>
      </td>
    </tr>
    <tr>
      <td><label for='address_region'>Область/край/республика</label></td>
      <td><input class='region_field' id='address_region' name='address[region]'></td>
    </tr>
    <tr>
      <td><label for='address_area'>Район</label></td>
      <td><input class='area_field' id='address_area' name='address[area]'></td>
    </tr>
    <tr>
      <td><label for='address_city'>Город/село</label></td>
      <td><input class='city_field' id='address_city' name='address[city]'></td>
    </tr>
  </table>
</form>

Javascript-код (дюже подробнейший, с уведомлением пользователя, отловом ошибок и исправлением индекса)

jQuery(document).ready(function($){
  $('.postcode_field').on('keyup change', function () {
    // Найдём все поля
    var postcode_field = $(this);
    var form = postcode_field.parents("form");
    var region_field = $('.region_field', form);
    var area_field   = $('.area_field', form);
    var city_field   = $('.city_field', form);
    // Очистим все поля
    region_field.val('');
    area_field.val('');
    city_field.val('');
    // Если индекс введён всецело - загрузим информацию о нём
    var postcode = this.value;
    if (postcode.length == 6) {
      jQuery.ajax({ 
        dataType: "jsonp",
        url: 'http://postindexapi.ru/' postcode '.json?callback=?',
        beforeSend: function() { // Уведомим пользователя, что загрузка идёт
          $("td:last-child p.description.notice, td:last-child p.description.alert", postcode_field.parents("tr")).remove();
          $('<p></p>').text("Загрузка…").appendTo($("td:last-child", postcode_field.parents("tr")))
        },
        success: function(data){
          postcode_field.val(data.index);
          region_field.val(data.region);
          area_field.val(data.area);
          city_field.val(data.city);
          if (data.index != postcode) {
              var message = "Вы ввели устаревший почтовый индекс: " postcode ", ваш нынешний индекс: " data.index;
              $('<p></p>').text(message).appendTo($("td:last-child", postcode_field.parents("tr")))
          }
        },
        error: function (jqxhr, status, e) {
          var message = 'Случилась оплошность при загрузке адреса по почтовому индексу!' e;
          if (e == 'Not Found') message = 'Почте России такой почтовый индекс не знаменит';
          if (status == 'timeout') message = 'Сервер с почтовыми индексами не отвечает. Испробуйте ещё раз.';
          $('<p></p>').text(message).appendTo($("td:last-child", postcode_field.parents("tr")))
          console.debug(jqxhr, status, e);
        },
        complete: function () { // Уберём плашку
          $("td:last-child p.description.loading", postcode_field.parents("tr")).remove();
        }
      });     
    }
  });
});

И, вуаля, при вводе индекса нам автоматом подставляется область, город и так дальше. Заодно, бонусом, мы можем исправлять устаревшие индексы на актуальные (дюже Зачастую у людей записаны адреса родственников с теснее безнадёжно устаревшими индексами).

Ещё штришок: Дабы удерживать базу неизменно свежей, сотворим rake-таск, тот, что будет запускаться по крону, скажем, раз в две недели и всё это делать за нас (в Gemfile у вас должен быть gem 'nokogiri', дозволено с require: false):

require 'open-uri'
require 'fileutils'
require 'nokogiri'

namespace :post_index do

  desc 'Update used post indices database to latest'
  task update: :environment do
    # Get info about post indices database
    url_prefix = 'http://info.russianpost.ru/database'
    doc  = Nokogiri::HTML(open("#{url_prefix}/ops.html"))
    file = doc.at_css('a[name=newdbdata] table tr:last-child td:nth-child(4) a').attr :href
    FileUtils.mkdir_p "#{Rails.root}/tmp/post_indices"
    dir = Pathname.new("#{Rails.root}/tmp/post_indices")
    filepath = Pathname.new("#{dir}/#{file}")
    filepath_success = Pathname.new("#{dir}/#{file}.success")
    if filepath.exist? and filepath_success.exist?
      puts 'Already up-to-date.'
    else
      # Download, unzip, rename and convert post indices file
      sh "wget #{url_prefix}/#{file} -O #{filepath}"
      sh "unzip -o #{filepath} -d #{dir}"
      dbf_filename = filepath.to_s.gsub /.zip$/, '.DBF'
      sh "cp -f #{dbf_filename} #{dir}/post_indices.dbf"
      sh "pgdbf -u #{dir}/post_indices.dbf | iconv -f CP866 > #{dir}/post_indices.sql"
      # Import in database
      config = Abitur::Application.config.database_configuration[::Rails.env]
      dbh, dbu, dbp, db = config['host'], config['username'], config['password'], config['database']
      sh "PGPASSWORD=#{dbp} psql -U #{dbu} -w -h #{dbh} #{db} < #{dir}/post_indices.sql"
      # Clean up
      FileUtils.rm [dbf_filename, "#{dir}/post_indices.dbf", "#{dir}/post_indices.sql"], force: true
      FileUtils.touch filepath_success
    end
  end

end

Резюме

Плюсы: простота внедрения, применения и поддержания в актуальном состоянии, малый вес
Минусы: невысокая подробность (только до населённого пункта), ВСЕ ГОРОДА КАПСОМ, ПОЧТА РОССИИ, ДЛ? чЕГО?

И для самых ленивых

Ну, и напоследок. Если же вам такая мелочь понравилась, но вы яростно не хотите тащить эту информацию к себе в приложение, то намеренно для вас я сделал мини-сервис postindexapi.ru. Тот, что делает как раз то, что я описал выше — отдаёт информацию об индексе в JSON. Пользуйтеся на здоровье! Инструкции прилагаются.

И автор не погнушается попросить донату.

Автор с благодарностью примет всякие средства на поддержку обслуживания postindexapi.ru.
PayPal: envek@envek.name
WebMoney: R157729290120
С не меньшею благодарностью принимаются так же pull request’ы и bug report’ы, а так же всякие советы и пожелания в гитхаб-репозитории: github.com/Envek/postindexapi.ru

Спасибо за внимание.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB