Author: 芳草苑主

  • Smtp through my server in gmail

    Google recommend sending through SMTP servers for professional domains. In most cases, it is not necessary unless you do not want your email recipients pick up your primary Google Apps domain information when you use “send mail as” facility.

    All you need is getting a SMTP server ready to work with Google. Setup in Gmail is quite easy.

    Set my own SMTP in Gmail Step 1
    Set my own SMTP in Gmail Step 1
    Set my own SMTP in Gmail Step 2
    Set my own SMTP in Gmail Step 2

  • 1and1 server London zoneinfo is invalid

    I can not believe it! One of the files come with 1and1 CentOS server installation is invalid. I do not know whether other types of servers from 1and1 have the same situation, but I am using 1and1 cloud server 64bit. The damaged file is /usr/share/zoneinfo/Europe/London. Every method I tried to set timezone to London (for now it is BST: British Summer Time), the system resets it to EDT: Eastern Daylight Time.

    Normally I know how to set timezone on server, but cloud server is new to me. So when I see my methods do not work, my first reaction is looking for some secret method that works on cloud server. I have tried different ways to set timezone before I ever think about the London zoneinfo file is invalid. In a total hopelessness, I upload my PC’s /usr/share/zoneinfo/Europe/London from Fedora to CentOS, and it works.

    Other zoneinfo files are OK as I observed.

  • My approach to a live chat extension for Magento

    试用了两个 Magento live chat extension,都不怎么好用。

    一个是 Luxe_Yalc,基于 Google chatback,是我想要的,因为 Android 手机可以让我 7/24 在线。可惜 Luxe_Yalc 试图凭用户输入 Google Account 的信息去获取 Google chatback html,但有 bug,至少在我机器上运行获取不了那段 html。我想写个 Magento live chat extension 用不着这么复杂,直接让用户自行登录 Google Account,拷贝出 chatback html,粘帖入 Magento 后台就可以。这样做的好处是,只要 Google 继续支持 chatback,怎么改变 chatback html,用户都能应变。

    一个是 MagentoLiveChat,基于本地服务器的 live chat,不依赖于第三方服务,精神可嘉。看上去功能很多,还支持多个 operators。但我想还是等到企业发展壮大到需要多个在线客服的阶段再考虑这个 extension。

  • Magento 1.4.2.0 extension key change

    今天有闲,下载了 Magento 1.4.2.0 beta 1 来体验,同时用 Magento Connect 安装了几个 livechat extension 来体验。其实我不太喜欢 Magento Connect 来安装 extension(曾经很喜欢),因为:

    • 很多时候仅在 Magento fresh installation 可用,随着安装的扩展越来越多、Magento 自身的升级,过一段时间后想再用 Magento Connect 安装点什么就发现启动不了;
    • 用 Magento Connect 升级 Magento 自身也不可靠,碰到几次在升级过程中断,造成前后台全部瘫痪,只好用传统的 ssh 或 ftp 安装来升级。

    说远了。因为 Magento Connect 里的 extensions 只能用 Magento Connect 来安装(或许有别的办法?),我就老老实实拷贝了 extension key 粘贴,结果 Magento Connect 拒绝工作,说“couldn’t resolve host”,我晕了一下,不过很快找到原因:

    Magento 1.4.2.0 起把 extension key 的规则改了,比如从 magento 网站上找来 extension key

    magento-community/EXTENSION_NAME

    应稍作修改,改成能被 Magento 1.4.2.0 认可的 extension key

    http://connect20.magentocommerce.com/community/EXTENSION_NAME

  • Magento extension: bxgy 0.1.1 is released

    Bxgy 0.1.0 is reported fail to work when raising orders from backend. It is because of

    
    $quote = Mage::getSingleton('checkout/cart')->getQuote();
    

    Now

    
    $quote = $item->getQuote();
    
    

    for bxgy rule to process regardless whether quote is frontend or backend.

    Download bxgy 0.1.1BuyXGetY.tar.gz

    2011/02/21 Update: please checkout a newer release. Always leave comments on the newest release post. The comment on this post is closed.

  • 3 international call saver coverage

    With Add International Saver you can make unlimited (literately 3,000 minutes) calls from the UK to 31 destinations for £15 per month. You just need to dial 388 and then the international number. International Saver lets you call standard landline & mobile numbers in : Canada, China, Hong Kong, Hawaii, Puerto Rico, Singapore, Thailand and USA. You can also from the UK to standard landlines only, in Australia, Austria, Azores, Belguim, Denmark, France, Germany, Italy, Ireland, Japan, Luxemburg, Malaysia, Maderia, Netherlands, New Zealand, Norway, Poland, Portugal, Spain, Sweden, Switzerland, South Korea and Taiwan.

    写下这个倒不是推荐用 3 来打国际电话,纯属有感而发:3 388 国际电话服务在中国人群里口口相传就成了只能打中国的电话。我心想不太会吧,一个英国公司能把市场细分到中国人群单独对待,那真是了不起。上网一查,果然,服务是全球性,只是顾客领会产品信息是过滤性的阅读,所以以讹传讹。

  • Magento user be warned: eav_entity_store has realtime sales data

    最近在一个 Magento 网站上大幅调整了 catalog structure。我先在测试服务器上调整产品属性、目录属性等,然后把测试服务器数据库里所有 catalog 和 eav 开头的表导入到生产服务器。因为生产站点的销售没有中断,我不能简单地从测试服务器往生产服务器导入整个 magento 数据库。

    这次升级初看很成功,随后就发现百密中有一疏。我装有 protx standard (for SagePay Form integration),顾客在重定向到 SagePay 付款时,表单预填的数据是别人的。原因是测试服务器的跟销售有关数据是生产服务器若干天前的,eav_entity_store 表里保存有 increment_last_id,我从测试服务器往生产服务器导入所有 catalog 和 eav 开头的表,导致 magento 再次分配几天已分配过的 order ID 给新订单。如果顾客在重定向到 SagePay 后点击 cancel,会导致同订单号的老订单 status change to cancelled。

    ID 重复是一个很低级的错误,我不应该去导入 eav_entity_store 表。我是知道这张表的作用的,这个错误应该归咎于我考虑不周到。

    Protx standard 这个模块也不够周到,我用的版本比较老,不知新版是否在这方面有改进。

  • Visual programming using Google Apps Script

    Google 很强大,虽然我不止一次地说,但用了 Google Apps Script 以后,我还是想再说一次。

    Many of Google Products are helping people use the web. Google Apps Script help me visually programme route jobs.

    在工作流中,有很多变化着的因素,导致很多程序是一次性的。快速变化的环境不要求程序很智能,但要能快速响应业务的变化。很多时候我很郁闷——因为编程速度跟不上业务速度,导致人工重复劳动。

    Google Apps Script 是目前跟我理想中的 crm, accounting 最接近的解决方案。

  • Install Zend Server with Plesk

    据说 Zend 正在跟 Plesk 探讨怎么让他们的产品相互兼容。

    我没那么高深,无法让 Zend Server 完全兼容 Plesk,但可以做到——

    前台用上 Zend Server 版的 php (Plesk 前后台使用两个安装的 php),尽管 Plesk 后台误认为 php module not installed。我强行修改了 psa 数据库里的数据,改了什么我不记得了。说实话,把 Zend Server 和 Plesk 跑在一起意义也不大。

    Parallels Installed Components
    Parallels Installed Components
    Parallels with php 5.3.2 from Zend Server
    Parallels with php 5.3.2 from Zend Server
    Parallels php not installed
    Parallels php installed but showing as not installed
  • A support class to pluralise English words in Magento

    我写这个类更多地是为了补习一下英文。顺便说一下,我会逐渐把更多的 support classes 归于 Msdk module,意思是 Magento SDK.

    An ideal way to learn IT and English as a foreign language at a time.

    
    <?php
    class Qian_Mdsk_Helper_Plural extends Mage_Core_Helper_Abstract
    {
    /**
    * auto is a wrapper. it calls another method by language settings
    * @param int $nr
    * @param string $singularWord
    * @return string
    */
    public static function auto($nr, $singularWord) {
    //if english
    return self::english($nr, $singularWord, 's');
    }
    
    public static function english($nr, $singularWord, $pluralSuffix = 's') {
    if (abs($nr) == 1) {
    return "$nr $singularWord";
    }
    
    $no = Mage::helper('corex')->__("No");
    //If a word has more than one form of plural, and if the commonly used form is regular, the word will not be included in this dictionary.
    //e.g. roof => roofs (irregular) or rooves (regular)
    $dictionary = array(
    //sh rule exception
    'fish' => 'fish',
    
    //o rule exception
    'canto' => 'cantos',
    'homo' => 'homos',
    'piano' => 'pianos',
    'portico' => 'porticos',
    'pro' => 'pros',
    'quarto' => 'quartos',
    'kimono' => 'kimonos',
    'zoo' => 'zoos',
    'igloo' => 'igloos',
    'kangaroo' => 'kangaroo',
    'kniazhestvo' => 'kniazhestva',
    
    //x rule exception
    'matrix' => 'matrices',
    'vertex' => 'vertices',
    
    //s rule exception
    'alumnus' => 'alumni',
    'corpus' => 'corpora',
    'focus' => 'foci',
    'genus' => 'genera',
    'prospectus' => 'prospecti',
    'radius' => 'radii',
    'syllabus' => 'syllabi',
    'viscus' => 'viscera',
    'fungus' => 'fungi',
    'terminus' => 'termini',
    'uterus' => 'uteri',
    'Atlas' => 'Atlantes',
    
    'species' => 'species',
    'series' => 'series',
    'blues' => 'blues',
    'axis' => 'axes',
    'testis' => 'testes',
    
    //y rule exception
    'Germany' => 'Germanys',
    'Harry' => 'Harrys',
    
    //f rule exception
    'staff' => 'staff',
    'flagstaff' => 'flagstaffs',
    'proof' => 'proofs',
    
    //other exception
    //singular and plural are identical
    'people' => 'people',
    'deer' => 'deer',
    'moose' => 'moose',
    'sheep' => 'sheep',
    'bison' => 'bison',
    'salmon' => 'salmon',
    'pike' => 'pike',
    'trout' => 'trout',
    'swine' => 'swine',
    'aircraft' => 'aircraft',
    'head' => 'head',
    'stone' => 'stone',
    'benshi' => 'benshi',
    'otaku' => 'otaku',
    'samurai' => 'samurai',
    'Māori' => 'Māori',
    'marae' => 'marae',
    'waka' => 'waka',
    
    //very irregular exception
    'child' => 'children',
    
    'alumna' => 'alumnae',
    
    'mouse' => 'mice',
    'louse' => 'lice',
    
    'tooth' => 'teeth',
    'foot' => 'feet',
    'goose' => 'geese',
    
    'automaton' => 'automata',
    'criterion' => 'criteria',
    'phenomenon' => 'phenomena',
    'polyhedron' => 'polyhedra',
    
    'addendum' => 'addenda',
    'agendum' => 'agenda',
    'consortium' => 'consortia',
    'corrigendum' => 'corrigenda',
    'datum' => 'data',
    'medium' => 'media',
    'memorandum' => 'memoranda',
    'millennium' => 'millennia',
    'symposium' => 'symposia',
    
    'stigma' => 'stigmata',
    'stoma' => 'stomata',
    'schema' => 'schemata',
    'dogma' => 'dogmata',
    'lemma' => 'lemmata',
    
    'beau' => 'beaux',
    'château' => 'châteaux',
    'tableau' => 'tableaux',
    
    'Inuk' => 'Inuit',
    'inukshuk' => 'inukshuit',
    
    'phalanx' => 'phalanges',
    
    );
    
    if (isset($dictionary[$singularWord])) {
    $pluralWord = $dictionary[$singularWord];
    }
    else {//some clever conversion
    $end = substr($singularWord, -3);
    if ($end == 'man') { //checking last 3 characters
    $pluralWord = substr($singularWord, 0, -3) . 'men';
    }
    elseif ($end == 'sis') {
    $pluralWord = substr($singularWord, 0, -3) . 'ses';
    }
    else {
    $end = substr($singularWord, -2);
    if ($end == 'ch' || $end == 'sh') {
    $pluralWord = $singularWord . 'es';
    }
    elseif ($end == 'fe') {
    $pluralWord = substr($singularWord, 0, -2) . 'ves';  //e.g. knife => knives, wife => wives
    }
    else {
    $end = substr($singularWord, -1);
    if (strpos('sxo', $end) === false) { //checking last character
    $pluralWord = $singularWord . 'es';
    }
    elseif ($end == 'f') {
    $pluralWord = substr($singularWord, 0, -1) . 'ves'; //e.g. half => halves
    }
    elseif ($end == 'y') {
    $secondLast = substr($singularWord, -2, 1);
    if (strpos('aeiou', $secondLast) === false) {
    $pluralWord = substr($singularWord, 0, -1) . 'ies'; //e.g. lady => ladies
    }
    else {
    $pluralWord = $singularWord . $pluralSuffix; //e.g. boy => boys
    }
    }
    else { //last rule
    $pluralWord = $singularWord . $pluralSuffix;
    }
    }
    }
    
    }
    
    if ($nr == 0) {
    return "$no $pluralWord";
    }
    else {
    return "$nr $pluralWord";
    }
    }
    
    }