CakePHP Voucher/Discount 代码系统

CakePHP Voucher/Discount code system

我查看了 Google 一些关于此的 samples/solutions,例如 Creating Discount Code System (MySQL/php) 但我没有找到好的解决方案。

我的情况是这样的,我有一个平台,用户应该在该平台上有虚拟货币余额,并可以为其购买虚拟物品。现在有实施代金券和折扣的愿望。会有不同类型的代码,比如购买商品时提供 50% 折扣的代码、x 数量的额外商品(有或没有最低商品数量)、只是获得某种货币的代码,或者给推荐人一些东西的参考代码.

我将其实现为 Campaign 和 CampaignType,其中第一个包含活动信息,第二个包含操作信息。

结构如下:

-- Table structure for table `cake_campaigns`

CREATE TABLE IF NOT EXISTS `cake_campaigns` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 NOT NULL,
  `code` varchar(100) COLLATE utf8_bin NOT NULL,
  `type_id` varchar(50) CHARACTER SET utf16 COLLATE utf16_bin NOT NULL DEFAULT '1',
  `value` int(10) unsigned NOT NULL DEFAULT '5' COMMENT 'Percentage or amount',
  `min_amount` bigint(20) unsigned NOT NULL DEFAULT '0',
  `owner_id` bigint(20) unsigned NOT NULL,
  `created` datetime NOT NULL,
  `active` tinyint(1) unsigned NOT NULL DEFAULT '1',
  `single_use` tinyint(1) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `code` (`code`),
  KEY `owner_id` (`owner_id`),
  FULLTEXT KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=4 ;

-- Table structure for table `cake_campaign_types`

CREATE TABLE IF NOT EXISTS `cake_campaign_types` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 NOT NULL,
  `unit` varchar(10) CHARACTER SET utf16 NOT NULL DEFAULT '%',
  `multiplier` double(10,8) NOT NULL DEFAULT '0.01000000',
  `type` varchar(50) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=7 ;

目前我的逻辑是,当使用活动时,操作是根据活动类型的名称进行的,例如在购买逻辑中:

if (isset($this->request->data['Purchase']['code'])) {
    $code = $this->request->data['Purchase']['code'];
    $campaign = $this->Campaign->findByCode($code);
    $this->Campaign->id = $campaign['Campaign']['id'];

    // campaign no longer active
    if ($this->Campaign->field('active') == 0) $code = false;

    if ($this->CampaignLog->find('first', array('conditions' => array(
            'user_id' => $this->User->field('id'),
            'campaign_id' => $this->Campaign->field('id'),
            'activated' => 1,
        )))) $code = false; // code has already been used

    unset($this->request->data['Purchase']['code']);
} else $code = false;

// Some purchasing logic here

if ($code) {
    $this->CampaignLog->create();
    $this->CampaignLog->save(array(
            'campaign_id' => $this->Campaign->field('id'),
            'user_id' => $this->User->field('id'),
            'activated' => 1,
            'source' => $this->Session->read('referrer'),
            'earnings' => $earned,
            'created' => strftime('%Y-%m-%d %H:%M:%S'),
        ));

    if ($this->Campaign->field('single_use') == 1) {
        $this->Campaign->saveField("active", 0);
    }

    // Apply code here
}

现在,我的问题是: 应用这些代码的最佳做法是什么,因为我对在所有可能的代码类型中使用 if-then-else 或 switch-case 感到有点不安。但现在,由于有太多不同的东西(例如折扣 - 百分比或固定金额),那么这似乎是唯一的选择。 也许代码的 structure/logic 应该不同?

在我看来这已经很简单了,将其与购买相结合将是了解更多问题的最佳选择。假设我们有 $this->request->data['price'] 作为价格,那么我们有一个 type_id1 代表折扣的例子。

我们所要做的就是得到 value 并计算百分比方程,这样就可以像

$discount = floatval('0.' . $this->Campaign->value);
$finalPrice = $this->request->data['price'] * $discount;

如果我们在 switch 案例中实现它以隔离它们的逻辑,那就更好了。这可能取决于您如何实现它,但这是概念的要点。

检查 cart plugin it is using events 的所有内容,没有任何内容是硬编码的,使用这种方法非常灵活。

one method that is fired whenever the cart needs to be recalculated. Inside it calls other methods to calculate taxes and discounts.

通过活动实现这一点的优势在于,以后可以很容易地通过额外折扣或税收计算来扩展。

随时查看插件的整个代码,它不是一个简单的实现,涵盖购物车数据的 cookie、会话和数据库存储,并且有很多事情的事件。