субота, 9 квітня 2016 р.

Pilgrim - casual classic 11302-00401

В житті кожного порядного та небайдужого громадянина™ виникає ситуація, коли він нарешті готовий замовляти через інтернет не лише побутову техніку з Китаю, але й одяг, який приміряти можна лише після отримання. Так, він може не підійти, або виглядати геть не так, як на фотографіях. Проте інтернет магазини намагаються мінімізувати ці незручності за допомогою різних акцій, сервісної підтримки і супроводу товару аж поки клієнт не буде задоволеним, що конвертується магазину в заробіток, покращення репутації, отримання лояльного клієнта тощо.

Трішки передісторії: Про магазин Pilgrim я дізнався внаслідок їх активної маркетингової кампанії в червні минулого року. На той момент я шукав українських виробників (якщо пригадуєте, була така хвиля зацікавленості речами, які роблять у нас), і вибір на «Пілігримів» пав в першу чергу тому, що вони мали привабливу рекламу, гарне ім'я, були зроблені в Україні (так, зірки стали так, як мало бути). Тому, десь підсвідомо я вирішив, що наступна пара взуття (а це була модель 
11302-00401) буде придбана саме у них.
Ну, а тепер власне до самого процесу замовлення (пишу по гарячих слідах, тому можете сприймати це якраз як перше враження), яке я робив недільного вечора. Система замовлення є досить простою, проте, для тих, хто читає уважно, може впасти у вічі те, що у рекомендаціях для споживача пропонується визначити свій розмір і повноту, проте на сторінці замовлення просять вказати лише розмір. Ну, Бог з ним, можливо я просто десь щось пропустив. Тим паче, що неділя, а в понеділок вже буду займатися іншими справами.

В понеділок зранку, до мене зателефонувала менеджер Наталя (до її честі, вона дзвонила декілька разів, аж поки додзвонилась до мене), яка перепитала ще раз, чи я все вірно замовив. Я підтвердив, всі дані , і розказав, що на сайті пропонується визначити як розмір так і повноту ноги, але на сторінці замовлення можна вказати лише розмір ноги. Вона мені пообіцяла вислати лист з посиланням, де можна виміряти і вказати повноту ноги, проте, це було посилання на ту ж саму сторінку, яку я вже бачив. Тим не менше, у вівторок ввечері (у зв'язку зі своїм навантаженнями), я спромігся їй передзвонити, та уточнити номер ноги, включаючи розмір у сантиметрах, а також домовитися, що моє замовлення виїде до мене у середу (оскільки їде з Харкова, то у Львові очікується у п'ятницю). Правда про повноту - ані слова. Хоча я вже бачив один відгук, у якому інший клієнт казав, що взуття йому не підійшло саме по повноті. Тому деякі побоювання все ж були. 

Сьогодні зранку, я таки забрав пакунок з «Нової пошти». Фірмова коробка білого кольору з пілігримом, запакована у плівку, через два дні дісталась до свого власника.

Вигляд зверху
Вигляд збоку
Всередині самої коробки, окрім пари взуття виробник поклав:
а) календар-промоакція з кодом на знижку при замовленні наступної пари;
б) фірмовий паперовий подарунковий пакет;
в) видаткову накладну;
г) заяву на повернення товару та грошових коштів.
Коробка взуття і її вміст
Останній пункт вразив наповал: виробник пропонує при поверненні товару або замінити модель/розмір, або ж повернути кошти, при чому повернення може бути на картку з якої здійснювалась оплата, на банківський рахунок або ж поштовим переказом. Тобто жодних обмежень і суцільна турбота про покупця та його комфорт. Ось вам зразок якісного українського магазину, у якому хочеться купувати і надалі.

Перше враження від взуття - сидить як влите.

Чого б хотілося ще? Щонайменше двох речей: інструкції по догляду за взуттям та більш жорсткого картону у коробці, яка трішки прим'ялась при транспортуванні.

Ну, і зробіть щось з повнотою ноги, невже люди даремно її вимірюють?

понеділок, 1 лютого 2016 р.

Accessing MS Access from python with Cyrillic table names

My today's issue is quite interesting and is related to the data migration from MS Access to some regular (and more widely-used) database, i.e. MySQL. So we have as input a database, created in the MS Access 2000 (supposed) with the Cyrillic tables, that contains near 5k of sensible records. And expected result should be any DB that is supported by SQL Alchemy (right now it is MySQL, but I believe it will be easy to migrate to any other). And here is the most complex part: "How"?

Firstly I needed some way to provide ODBC  support for my Linux (Windows users/developers are more lucky at this point) as well as driver for access to MDB files. These packages provide such support for Debian:
  • unixodbc
  • odbcinst
  • libodbc1
  • libiodbc2
  • odbc-mdbtools
I got this list of packages from amirkdv, who implemented ODBC module for PHP. [Note: later I found a plenty of other docs about this subject, so I'm not good at Googl'ing at all]. Among other drivers there was also a web-page for unixodbc.org and Easysoft's page, who asked near 500 pounds for their library. Maybe it worth that money, but I need such access for one-time operation, so that's not my case right now.

So final command on my Debian system looked like:
$sudo apt-get install unixodbc odbcinst odbc-mdbtools

Files /etc/odbc.ini and /etc/odbcinst.ini were created after the installation and the latter one contained following lines:
[MDBTools]
Description=MDBTools Driver
Driver=libmdbodbc.so
Setup=libmdbodbc.so
FileUsage=1
UsageCount=1

It was enough for my case. The line "[MDBTools]" in the mentioned above file states for the name of the used driver, that should be indicated for granting access to the database.

At this point system's preparation is over, and it is a time, to look around about libraries that should provide access to the DB from the python. I discovered few of them:
  • pyodbc - outdated and I discovered this a bit later;
  • pypyodbc;
  • sqlalchemy-access - outdated as well.
Unfortunately, pyodbc failed to connect to the database, so I've been forced to use pypyodbc as the only possible way at that moment. Being inspired by usage examples for pypyodbc I finished with something like this: 

import pypyodbc
from os.path import abspath

drv ='MDBTools'
db_file = abspath('./pl.mdb') # Here "pl.mdb" is my input file
con = pypyodbc.connect("DRIVER={};DBQ={}".format(drv, db_file))
cur = con.cursor()

tables = list(cur.tables())

# Get list of tables from the file
for tbl in tables:
  print tbl


And got something like that:
('', '', '\xd0\x92\xd1\x83\xd0\xbb\xd0\xb8\xd1\x86\xd1\x96\xd0\x9b\xd1\x8c\xd0\xb2\xd0\xbe\xd0\xb2\xd0\xb0', 'TABLE', '')
('', '', '\xd0\x9d\xd0\xb0\xd1\x81\xd0\x9f\xd1\x83\xd0\xbd\xd0\xba\xd1\x82\xd0\xb8\xd0\x9b\xd0\x9e', 'TABLE', '')
('', '', '\xd0\xa2\xd0\xb8\xd0\xbf\xd1\x8b', 'TABLE', '')
('', '', '\xd0\xa2\xd0\xbe\xd0\xb2\xd0\xb0\xd1\x80\xd1\x8b', 'TABLE', '')
('', '', '\xd0\xa4\xd1\x96\xd1\x80\xd0\xbc\xd0\xb8\xd0\x9f\xd0\xbe\xd1\x81\xd1\x82\xd0\xb0\xd1\x87\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd0\xb8\xd0\xba\xd0\xb8', 'TABLE', '')

Here I should shout "Hooray! I did it!", but unfortunately, there is no reason for joy. As you may notice, tables are named by Cyrillic names, so now I should deal with them in some way.
The only solution that came into my mind was to call SQL statement as Unicode string, with the table's name encoded as regular string, i.e.:

sql_statement = u'SELECT * FROM "\xd0\x92\xd1\x83\xd0\xbb\xd0\xb8\xd1\x86\xd1\x96\xd0\x9b\xd1\x8c\xd0\xb2\xd0\xbe\xd0\xb2\xd0\xb0"' 
res = cur.execute(sql_statement).fetchall()
for item in res:
  print item

So, I got a list of tuples like this one (stripped version), from which records can be converted into regular Unocode.
('\xd0\x94\xd0\xb6\xd0\xb5\xd1\x80\xd0\xb5\xd0\xbb\xd1\x8c\xd0\xbd\xd0\xb0',)
('\xd0\x94\xd0\xb7\xd0\xb8\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb8 \xd0\x84.',)
('\xd0\x94\xd0\xb8\xd0\xb2\xd1\x96\xd0\xb7\xd1\x96\xd0\xb9\xd0\xbd\xd0\xb0',)
('\xd0\x94\xd0\xb8\xd0\xba\xd1\x82\xd0\xbe\xd0\xb2\xd0\xb0',)
('\xd0\x94\xd0\xb8\xd1\x82\xd1\x8f\xd1\x87\xd0\xb0',)


The converted version of the records is:

Джерельна
Дзиндри Є.
Дивізійна
Диктова
Дитяча

And now it is a time for "Hooray!!!!"