Extend Magento inventory management

Magento inventory management is very basic – only an Inventory Qty figure. Strictly speaking, it is not an “in-stock” figure, but an “orderable”. Because orders keep coming in but you only do despatch once a day, Magento inventory quantity changes upon order is placed online, so you can not tell how many pieces of a product sitting in the warehouse.

Use only one figure to manage inventory is not enough. Imagine this scenario:
You are doing stocktake someday. At the time of last despatch, Magento inventory quantity of product X is 100. Stocktaking takes many hours, and when it finishes, Magento inventory quantity has changed to 80. If you physically count product X as 95, you can not simply update Magento inventory figure to be 95. Instead you should change it to 75 (worked out as 80 – 100 + 95). It is very easy to make such mistakes in stocktaking, but I have only Magento to blame – if stocktaking is based on a figure which is changing from time to time, it is not rock solid.

However, I am not thinking of introducing a 3rd party inventory management system to work with Magento, largely because I do not know which one can fit.

I am thinking of a simple extension to Magento – use 3 figures to show stock level from different concerts. Let’s clarify the terminology first.
Figure 1: inventory orderable, i.e. the existing Magento Inventory Qty;
Figure 2: inventory in-stock, i.e. how many pieces in the warehouse;
Figure 3: inventory coming, i.e. expected purchase.

  • When an order is placed, decrease inventory orderable
  • When an order is despatched, decrease inventory in-stock
  • When an order is cancelled before despatch, increase inventory orderable
  • When an order is cancelled after despatch, do nothing (some companies raise RMA at this point but we do not need it.)
  • When an order is returned, if goods in good condition, increase inventory orderable, and increase inventory in-stock
  • When a purchase order is placed (by us to our supplier), increase inventory coming
  • When a purchase order arrives, decrease inventory coming, increase inventory orderable, and increase inventory in-stock
  • When stocktake begins, snapshot inventory in-stock as inventory1
  • When stocktake ends, update inventory in-stock to inventory2, and add (inventory2 – inventory1) to inventory orderable

If all above events are logged, we have a kind of traceability. The log gives some clue to analyse where “inventory2 – inventory1” is from.

In case a customer asks “how many you have? I take them all”, we tell him/her inventory orderable.

In case we need find out “how many on hold (for late despatch)”, we use the balance between inventory orderable and inventory in-stock.

Inventory orderable (figure 1) is built-in with Magento. Inventory coming (figure 3) is not essential to stock control. We can introduce it after we have implemented inventory in-stock (figure 2).

Forget Magento bundle product, for now

Magento bundle product type 是我想往已久的:如果 A bundle 和 B bundle 都捆绑了某些数量的 simple product,它就可以实现 MRP 中 material consumed 功能。一开始我把所有产品都设为 bundle product,结果发现在后台 create order 时,一个可选产品也没有,原来这里只能把 simple product 加入订单。

总之,bundle product 的适用性大大有待提高,否则如同鸡肋。目前我全盘放弃了 bundle product,而且在新建产品选择 product type 时,我尽量使用 simple product,毫无疑问 simple product 的适用性是最高的。

5 approaches to customise Magento product

1. Configurable product. It is a built-in feature of Magento, and very easy to implement. No coding skills required. However, every sub product of the configurable must pre-exist as a simple product in Magento products. It is literally impossible to use it as made-to-order functionality, which aims at taking lots of parameters from customer’s input, calculating prices under millions scenarios.

2. Product custom options. Again it is a built-in feature of Magento, and easy to implement. But it is labour intensive to set it up if you have thousands of products of same set of custom options. Alternatively, you can buy an extension called Custom Options Template for less than $100. But I do not like data redundancy. Also, custom options on its own can not build the prices on the fly.

3. Made-to-order extension (MTO) developed by metrofindings.com. It does not require coding, either. I must admit it is a promising extension to some business. However, I think the majority of business pricing models are much more complicated than this MTO module can dealt with. It is not possible to describe pricing just based on xml or cvs, as far as my business is concerned.

4. My favourite approach version 1.0. It is inspired by MTO module with two major differences.
a) All raw data are stored in database rather than external files so a backend administrator can manage data changes without uploading xml or cvs files. I think it is a bad idea to mix daily maintenance with programming.
b) All business logics (cost / profit calculation, supplier screening, etc) fully rely on programming. Because I am a programmer so it is easier for me to control the program to follow my business logics. But if you are not, you’d better find a programmer to do it rather than fiddling with xml. Your business logics are usually more complex than an xml can solve.

5. My favourite approach version 2.0. When I developed version 1.0, I did not think carefully about how to store custom options. I added fields to quote_item and order_item, and created a session to store what customer’s inputs before they were written to database. Because it was not Magento native way to store options, when it came to reorder, I had to take extra care of those options. So, in version 2.0, I am going to (I have not implemented it) create ONE simple product that will be used for customisation across ALL made-to-order products. This product will be assigned a full range of custom options. If some custom options do not apply to certain made-to-order products, just leave them blank. And most importantly, this product will have a custom option to store sku telling us from which product the customisation is based on. I assume this approach does not break Magento reorder process. I only need to change some view templates to show this special product’s sku, image, description properly.

Adobe Scene7 has scary prices

最近 Adobe Scene7 引起了我的注意,因为我的网站在多媒体表现方式上比较弱,而 Scene7 正是强项。

Scene7 有个 Dynamic Imaging component,可以用其他布料纹理替换照片模特身上的衣服。我想 photoshop 高手也做得到这种替换,可惜我不是,于是碰到有这个功能的傻瓜软件就很兴奋。我在线联系了 adobe 询价,第二天 adobe 给我打来了电话,和我聊得很愉快,就是报价有点吓人,Dynamic Imaging 至少得缴五千镑,而且是年费。

唉,那我宁可报名去学 photoshop。

How Magento cache Blocks HTML output

我曾错误地认为 Magento 安装后,只要启用 cache,Magento 就会缓存页面的大部分内容,比如,cms, product, category 的 content block。

直到今天第 N 遍看 Magento wiki,才意识到 Magento 初始只启用了很小一部分 block cache。细想之下,Magento 默认不缓存 content block 有一定的道理:各用户对内容缓存的要求不一而足,所以 Magento 把这个问题留给用户自己去思考。

Block cache 有三个参数,cache_lifetime 顾名思义,cache_tags 关系到 cache 何时更新,cache_key 关系到 cache 有多少个版本。

在 Magento 目录下所有文件里搜索 cache_tags 这个词,我只发现它只出现在跟 Navigation (产品菜单),Footer (脚注),Adminhtml Menu (后台菜单) 相关的少数文件里。由此说明 Magento 根本没有缓存页面的最主要部分:content block。我联想到很久以前我在 Magento forum 上提问的一个问题:为什么 cache 只用掉了 0.5 MB 内存?当时我用的是memcached,结果热心人来问我 memcached 有没有安装正确啊,php-perl-memcache 有没有安装啊。就是没有人告诉我——一切正常,因为 Magento 尚未缓存页面主要内容

了解了 Magento cache 机制,再根据自己的实际情况对 product page 缓存 content block 就简单了:只要在 extends Mage_Catalog_Block_Product_View 的基础上加入

    protected function _construct()
    {
        $this->addData(array(
            'cache_lifetime'    => 86400,  //seconds
            'cache_tags'        => array(Mage_Catalog_Model_Product::CACHE_TAG . "_" . $this->getProduct()->getId()),
            'cache_key'         => $this->getProduct()->getId(),
        ));
    }

以此类推 cms page content block cache。Category page content block cache 稍微复杂一些,具体去看 Magento wiki。

设置 content block cache 对速度优化效果显著,我的 product page requests per second 指标提高了约 70%。

但我还是想让 Magento 跑得再快些,常说的那些 Magento 速度优化结果让我感觉不够畅快淋漓。我有个 page cache 想法,就是把整个页面缓存下来。Nginx 或其他的 web server 都有很好的机制去调度 html cache。据我测试,同一个静态内容的页面,保存为 html (Nginx 直接读取) 比保存为 php (经 php backend on socket or port 读取) 就快好几倍,这个结果让我对 page cache 充满了憧憬。

如使用 page cache,必须对页面中的 dynamic block (如 sidebar cart,recent viewed/compared products, etc)进行改写,简言之就是 load pages in two stages by ajax。Magento Enterprise Edition 就有 page cache feature,但我不清楚它是不是跟我同个思路。

与其买个 Magento Enterprise Edition,不过自己动手或请人实现 page cache。如果你恰好跟我有同样想法,请留言。

Solution to php fastcgi crashes

One of my servers is running Fedora + Nginx + php-cgi (spawned). I noticed sometimes php-cgi crashes without a reason or warning (Nginx gives out 500 error), and I have to spawn it again.

After some digging, I find exporting PHP_FCGI_MAX_REQUESTS to ENV cures the problem. As advised, I export PHP_FCGI_CHILDREN as well.

To achieve that, in detail, just add the following to the top of spawn bash script.

# Set these two env variables to reduce php-cgi crash
PHP_FCGI_MAX_REQUESTS=1000
export PHP_FCGI_MAX_REQUESTS
PHP_FCGI_CHILDREN=5
export PHP_FCGI_CHILDREN

Upgrade VirtualBox to 3.1.x

刚从国内回来,电脑上积累了很多更新。其中 VirtualBox 有了 3.1.2 r56127,我从 3.0.x 直接升级失败,抛出一大堆的文件冲突信息。

于是
yum remove VirtualBox -y
然后再
yum localinstall -y --nogpgcheck VirtualBox-3.1-3.1.2_56127_fedora11-1.x86_64.rpm
成功!

此删除和重安装操作无须备份和恢复原有的 guest OS(but as a good practice, you should backup files before major changes)。

Expires affects Firefox

我把 Magento 网店从 A 服务器迁移到 B 服务器后,发现一个问题:在 Firefox 下点 “Add to cart”,无论添加是否成功,系统没有提示(购物车有个选项是添加商品后留在当前页面),非得 F5 刷新后才能看到成功或错误信息。Safari 下正常,IE 下未实测。

我原以为是 Magento cache 的问题,但禁用 Magento cache 后问题依旧。而且,只有 B 服务器才有这样的毛病。想来半天,觉得跟服务器参数有关。

于是我查看了 Magento 在两台服务器的 http header,发现 B 服务器多了 cache 和 expiry 等 headers。这才特别关注了一下 nginx 的配置问题,发现 B 服务器的 server {} 里有一句 expires 1d; 不知这句是谁写到 nginx conf 文件里。这指名 Firefox 直接从本地读取,除非 F5。去掉 expires 这条目就好了。

Software navigation refactoring

回国看到老爸在用的一台电脑被一些流氓软件侵袭,深受其害。IE被篡改,连正常的网站都访问不了,我很痛恨。我又看到很多上网导航有误导之嫌,有那么多优秀的开源网站不去导,根本不符合我的网络价值观。所以,我也想倡导一下我的导航概念,帮助新手选择常用的软件。

安全杀毒

使用Windows,杀毒软件是不可或缺的。我个人认为卡巴斯基是最强的,但其他杀毒软件也不错,选什么不重要。我喜欢卡巴斯基和F-secure,很大程度上是因为他们向我校师生终生免费授权。

另外,在免费的世界里,还有AVG和Avira AntiVir两个选择。但如果你是完全意义上的新手(没有基本的防护意识,完全依赖杀毒软件来保护你),那不要贪图便宜,免费版功能不够全面,不适合你。尽管AVG和Avira AntiVir也有商业版,但我没用过,商业版还是去买卡巴斯基或F-secure吧。

瑞星杀毒
可免费使用六个月,国内占有率第一的杀毒软件。
卡巴斯基
来自俄罗斯的个人电脑安全软件,功能强劲。
NOD 32
国际知名的杀毒软件,占用内存资源较少。
江民杀毒
老牌杀毒软件,下载版可免费试用100天!
金山毒霸
金山毒霸具有三维一体的互联网防御体系。
诺顿杀毒
诺顿可以让你免受病毒、间谍、恶意软件的侵扰。

木马插件查杀

我认为有一款好的杀毒软件足矣,不需要专门的木马查杀软件。对一个软件要知根知底才能指望它来保护你,国内的流氓软件无处不在,多装一个软件就是多一分危险。

瑞星卡卡
具有反木马、广告拦截、插件免疫等功能的安全软件
360安全卫士
拥有查杀流行木马、清理恶评及系统插件等功能。
金山清理专家
查杀300多款恶意软件、插件的上网安全辅助软件。
QQ医生
针对盗取QQ密码的木马病毒的专杀工具!
木马克星
可查杀三万木马,让木马无处可逃的木马克星。
超级巡警
查杀并可辅助查杀各种木马、流氓软件和恶意代码等

聊天工具

聊天就是聊天,能打打字,最多传送一下语音和视频。Gtalk在这方面是最强的,安装程序短小精悍。如果你只需要文本聊天,甚至不需要安装软件,直接用Gtalk host模式在gmail,igoogle或自己网页里聊。如果你的朋友横跨gtalk, qq, msn, yahoo, icq, aol等,使用多合一的pidgin或Fring也不错。Pidgin和Fring没有眩目的广告,让你做到聊天就是聊天。

如果你追求等级积分,还会花钱去买皮肤什么的,那就是被IM公司牵着鼻子走了。在我看来,买这些增值服务跟打声讯聊天热线去烧钱没啥区别。

腾讯QQ
用户最多的即时通信(IM)软件,绝对的装机必备!
腾讯TM
腾讯推出面向办公用户的IM软件,适合办公一族。
微软MSN
微软出品的IM软件,深受办公白领人士钟爱。
移动飞信
飞信可以免费发短信,是中国移动推出的一款IM。
阿里旺旺
将淘宝旺旺与阿里巴巴贸易通整合在一起的新IM品牌
TOM-Skype
Skype是全球最清晰的网络电话,并具备IM功能。

Skype是voip解决方案中名气最大的,但绝不是最实惠的。如果你耐心google一下,相信会找到替代方案,不乏语音质量超好的voip provider。

下载工具
迅雷
基于P2SP技术的下载软件,下载速度强劲!

我从来不用迅雷,主要因为我听到的对迅雷的评价都是负面的,可能先入为主了。还有一个原因是迅雷不会走出国门,因而也无缘我的shortlist。
网际快车
全球最多人使用的老牌下载工具。

以前拨号上网的年代用过网际快车,现在似乎没有它的用武之地。它的广告也很烦人。
腾讯旋风
QQ旋风是腾讯公司推出的下载工具,界面清爽简单。

绝不会装的一个软件。
VeryCD电驴
基于eMule,由VeryCD团队开发的一个电驴下载软件。

很不错的软件。我也很欣赏 verycd.com,高可用性,堪称中国 web 2.0 的典范。偶尔一句“打死也不出弹窗”的title 让我为之喝彩许久。
BitComet
基于BitTorrent协议的高效p2p文件分享免费软件。

如果你还在找bt软件,那就用BitComet吧。我是说很多硬件都固件支持bt了,可以优先考虑。BitComet也支持ftp多协议,备着它也许是明智的选择。
Vagaa哇嘎
多点对多点共享软件,对下载等资源有很好的支持。

我没听说过,更没用过。