Search code examples
phpcakephplogicdiscount

CakePHP Voucher/Discount code system


I looked over Google for some samples/solutions about this, for example Creating Discount Code System (MySQL/php) but I haven't found a good solution.

My situation is such that I have a platform, where the user is supposed to have a balance in a virtual currency, and can buy virtual items for it. Now there's a wish to implement vouchers and discounts. There would be different kinds of codes, like one that gives 50% discount on purchasing items, x amount of extra items (with or without minimum item amount), just a code to get some currency, or a reference code that gives the referrer something.

I have implemented it as Campaign and CampaignType, where first holds the campaign info and second holds the action info.

Here's the structure:

-- 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 ;

Currently my logic is that when a campaign is used, then the action is according to CampaignType's name, for example in the purchase logic:

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
}

Now, my question is: What would be the best course of action on going about applying those codes, because I'm a bit queasy on going with if-then-else or switch-case through all the possible code types. But right now, since there's so many things that can be different (ex. Discount - in percentage or set amount), then that seems to be the only option. Maybe the structure/logic of the codes should be different?


Solution

  • It's already straightforward in my point of view, integrating it with the purchase would be the best bet in knowing further problems. Assuming that we have $this->request->data['price'] for the price, then we have an example type_id of 1 that represents as a discount.

    All we have to do is to get value and do percentage equation so that would be like

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

    Better if we implement it on a switch case to isolate their logic. It may depend on how you implement it but that's the gist of the concept.