Created
August 28, 2013 19:03
-
-
Save rondorkerin/6369904 to your computer and use it in GitHub Desktop.
payment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Payment | |
{ | |
private $provider; | |
private $test_mode; | |
public static $allowedProviders = array('authorize', 'paymenttest'); | |
const FREE_PLAN = 1; | |
const BASIC_MONTHLY_PLAN = 2; | |
const SECONDARY_MONTHLY_PLAN = 3; | |
const UNLIMITED_MONTHLY_PLAN = 4; | |
const BASIC_YEARLY_PLAN = 5; | |
const SECONDARY_YEARLY_PLAN = 6; | |
const UNLIMITED_YEARLY_PLAN = 7; | |
// name-indexed payment plan array | |
private $paymentPlans = array(); | |
// database IDs for specific billing plans | |
public static $paymentPlanIDs = array( self::FREE_PLAN => "FP", | |
self::BASIC_MONTHLY_PLAN => "BMP", | |
self::SECONDARY_MONTHLY_PLAN => "SMP", | |
self::UNLIMITED_MONTHLY_PLAN => "UMP", | |
self::BASIC_YEARLY_PLAN => "BYP", | |
self::SECONDARY_YEARLY_PLAN => "SYP", | |
self::UNLIMITED_YEARLY_PLAN => "UYP"); | |
public function __construct() | |
{ | |
$this->CI = get_instance(); | |
$this->CI->load->model('emailvariable_model'); | |
$this->CI->load->model('companyprofile_model'); | |
$this->CI->load->model('lead_model'); | |
$this->CI->load->model('companyplaninfo_model'); | |
$this->CI->load->model('paymentplan_model'); | |
$this->CI->load->model('companychargehistory_model'); | |
$this->CI->load->model('companybillinginfo_model'); | |
$this->CI->load->model('resellerplaninfo_model'); | |
$this->emailVariable = $this->CI->emailvariable_model; | |
$this->companyProfile = $this->CI->companyprofile_model; | |
$this->lead = $this->CI->lead_model; | |
$this->companyPlanInfo = $this->CI->companyplaninfo_model; | |
$this->paymentPlan = $this->CI->paymentplan_model; | |
$this->companyBillingInfo = $this->CI->companybillinginfo_model; | |
$this->resellerPlanInfo = $this->CI->resellerplaninfo_model; | |
$this->companyChargeHistory = $this->CI->companychargehistory_model; | |
$this->test_mode = FALSE; | |
// grab payment plans and stick them in class-scoped array | |
// indexed by enums | |
$paymentPlans = $this->paymentPlan->getAll(); | |
foreach ($paymentPlans as $plan) { | |
foreach (Payment::$paymentPlanIDs as $name => $planID) { | |
if ($plan['planID'] == $planID) { | |
$this->paymentPlans[$name] = $plan; | |
} | |
} | |
} | |
} | |
public function setProvider($providerName) | |
{ | |
if (!in_array($providerName, Payment::$allowedProviders)) { | |
return 0; | |
} | |
if ($providerName == "authorize") | |
{ | |
$this->CI->load->library('anetcim'); | |
$this->provider = $this->CI->anetcim; | |
} else if ($providerName == "paymenttest") { | |
$this->CI->load->library('paymenttest'); | |
$this->provider = $this->CI->paymenttest; | |
$this->test_mode = true; | |
} | |
return true; | |
} | |
/** | |
* This function should be run daily as a cron job | |
*/ | |
public function updateBillingPlans() | |
{ | |
$companies = $this->companyProfile->getAll(); | |
foreach ($companies as $company) { | |
// don't deal with inactive companies | |
if (!$company['isActive']) { | |
continue; | |
} | |
$clientPlan = $this->companyPlanInfo->get($company['id']); | |
// TODO: Notify clients that they need to input billing info | |
if (!$clientPlan) { | |
continue; | |
} | |
$billingSchedule = $clientPlan['schedule'] == 1 ? "monthly" : "yearly"; | |
$clientPlanID = $clientPlan['planID']; | |
$leadCount = $this->lead->getAllByCompany($company['id']); | |
$leadCount = count($leadCount); | |
// client is on the free plan. Upgrade them. | |
if ($clientPlanID == $this->paymentPlans[self::FREE_PLAN]['id']) { | |
if ($leadCount > $this->paymentPlans[self::FREE_PLAN]['threshold']) { | |
$today = new DateTime(); | |
$companyPlanInfo = $this->companyPlanInfo->get($company['id']); | |
$companyPlanInfo['startDate'] = $today->format('Y-m-d H:i:s'); | |
$this->companyPlanInfo->update($company['id'], $companyPlanInfo); | |
if ($leadCount <= $this->paymentPlans[self::BASIC_MONTHLY_PLAN]['threshold']) { | |
// upgrade to basic plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::BASIC_MONTHLY_PLAN]['id']); | |
} else if ($leadCount <= $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['threshold']) { | |
// upgrade to secondary plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['id']); | |
} else { | |
// upgrade to unlimited plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::UNLIMITED_MONTHLY_PLAN]['id']); | |
} | |
} | |
} | |
// client is on the basic monthly plan | |
if ($clientPlanID == $this->paymentPlans[self::BASIC_MONTHLY_PLAN]['id']) { | |
if ($leadCount > $this->paymentPlans[self::BASIC_MONTHLY_PLAN]['threshold']) { | |
if ($leadCount <= $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['threshold']) { | |
// upgrade to secondary plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['id']); | |
} else { | |
// upgrade to unlimited plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::UNLIMITED_MONTHLY_PLAN]['id']); | |
} | |
} | |
} | |
// client is on the secondary monthly plan | |
if ($clientPlanID == $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['id']) { | |
if ($leadCount > $this->paymentPlans[self::SECONDARY_MONTHLY_PLAN]['threshold']) { | |
// upgrade to unlimited plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::UNLIMITED_MONTHLY_PLAN]['id']); | |
} | |
} | |
// client is on the basic yearly plan | |
if ($clientPlanID == $this->paymentPlans[self::BASIC_YEARLY_PLAN]['id']) { | |
if ($leadCount > $this->paymentPlans[self::BASIC_YEARLY_PLAN]['threshold']) { | |
if ($leadCount <= $this->paymentPlans[self::SECONDARY_YEARLY_PLAN]['threshold']) { | |
// upgrade to secondary plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::SECONDARY_YEARLY_PLAN]['id']); | |
} else { | |
// upgrade to unlimited plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::UNLIMITED_YEARLY_PLAN]['id']); | |
} | |
} | |
} | |
// client is on the secondary yearly plan | |
if ($clientPlanID == $this->paymentPlans[self::SECONDARY_YEARLY_PLAN]['id']) { | |
if ($leadCount > $this->paymentPlans[self::SECONDARY_YEARLY_PLAN]['threshold']) { | |
// upgrade to unlimited plan | |
$this->companyPlanInfo->upgradeToPlan($company['id'], $this->paymentPlans[self::UNLIMITED_YEARLY_PLAN]['id']); | |
} | |
} | |
} | |
} | |
/** | |
* This function should be run daily as a cron job | |
* This function assumes updateBillingPlans is done every day | |
* which means the company billing status will be correct | |
*/ | |
public function processPayments() | |
{ | |
// get the current date and whether it's the first of the month. | |
$today = new DateTime(); | |
$firstOfTheMonth = $today->format('d') == '01' || $this->test_mode; | |
// if it's the first of the month, we need to bill resellers. | |
// we set up an associative array mapping reseller IDs to | |
// the total amount we will charge them | |
$resellerTotals = array(); | |
$companies = $this->companyProfile->getAll(); | |
foreach ($companies as $company) { | |
// we don't charge inactive clients | |
if (!$company['isActive']) { | |
continue; | |
} | |
$clientPlan = $this->companyPlanInfo->get($company['id']); | |
// we don't charge clients who are not on a billing plan | |
if (!$clientPlan) { | |
continue; | |
} | |
$billingSchedule = $clientPlan['schedule'] == 1 ? "monthly" : "yearly"; | |
$clientPlanID = $clientPlan['planID']; | |
$paidByCompanyID = $clientPlan['paidByCompanyID']; | |
$paidByMarketingFirm = ($paidByCompanyID != $clientPlan['companyProfileID']); | |
if ($paidByMarketingFirm && !$firstOfTheMonth) { | |
// if the company is being handled by a marketing firm, | |
// we only process payments on the first of the month | |
continue; | |
} | |
// don't charge free accounts | |
if ($clientPlanID == $this->paymentPlans[self::FREE_PLAN]['id']) { | |
continue; | |
} | |
// all companies past this point should be paying customers | |
$companyBillingInfo = $this->companyBillingInfo->getByCompanyID($paidByCompanyID); | |
if (!$companyBillingInfo) { | |
log_message('error', "companybilling info was null for company {$paidByCompanyID}"); | |
continue; | |
} | |
// ensure valid credit card | |
$cimnumber = $companyBillingInfo['cimNumber']; | |
$paymentID = $companyBillingInfo['customerPaymentProfileID']; | |
$validCreditCard = $this->provider->testCard($cimnumber, $paymentID); | |
if (!$validCreditCard) { | |
// TODO: Send a notification to company, to sharpspring admins | |
log_message('info', "company {$paidByCompanyID} has an invalid credit card."); | |
continue; | |
} | |
$lastChargeDate = $clientPlan['lastChargeDate']; | |
$lastChargeDate = $lastChargeDate ? new DateTime($lastChargeDate) : null; | |
$needsToPay = false; | |
if ($billingSchedule == 'monthly') { | |
// if user has never been charged | |
if (!$lastChargeDate) { | |
// if there's no last charge date, they're on the let-it-ride plan. | |
// if we've gotten to this point in the execution, the user has gone over their limit | |
// for free and we need to get them started paying today. | |
$needsToPay = true; | |
$chargeDate = $today; | |
} else { | |
// if a marketing firm is paying, we don't care about the last charge | |
// date because we charge the firm on the first of the month. | |
// OR they might be an individual account in which case we check that it's | |
// been a month | |
if ($lastChargeDate->diff($today)->m >= 1 || $paidByMarketingFirm) { | |
$needsToPay = true; | |
} | |
// check if it's been 12 months and we need to update discount | |
if($clientPlan['startDate']->diff($today)->y >= 1) { | |
$clientPlan['discount'] = $clientPlan['discountAfter12']; | |
} | |
$chargeDate = new DateTime($lastChargeDate->format('Y-m-d H:i:s')); | |
$chargeDate = $chargeDate->add(new DateInterval('P1M')); | |
} | |
} else if ($billingSchedule == 'yearly') { | |
// check if has freemonths | |
// check if its been >= 1 year + free months since payment | |
//set new lastpayment date to last year + 1 year. | |
$freeMonths = $clientPlan['freeMonths']; | |
if ($lastChargeDate) { | |
$needsToPay = $lastChargeDate->diff($today)->y >= 1 && | |
$lastChargeDate->diff($today)->m >= $freeMonths; | |
$chargeDate = new DateTime($lastChargeDate->format('Y-m-d H:i:s')); | |
$chargeDate = $chargeDate->add(new DateInterval("P1Y{$freeMonths}M")); | |
$clientPlan['freeMonths'] = 0; | |
if ($needsToPay) { | |
// it's been 12 + free months and we need to switch the client's discount | |
$clientPlan['discount'] = $clientPlan['discountAfter12']; | |
} | |
} | |
} | |
if (!$needsToPay) { | |
continue; | |
} | |
// get discount as percentage | |
$discount = $clientPlan['discount']; | |
if ($discount) { | |
$price = $clientPlan['price'] * (1.0 - ((float)($clientPlan['discount']))/100.0); | |
} else { | |
$discount = 0; | |
$price = $clientPlan['price']; | |
} | |
if (!$paidByMarketingFirm) { | |
// ding their credit card | |
$this->provider->chargeClient($paidByCompanyID, $price); | |
} else { | |
if (!array_key_exists($paidByCompanyID, $resellerTotals)) { | |
$resellerTotals[$paidByCompanyID] = $price; | |
} else { | |
$resellerTotals[$paidByCompanyID] += $price; | |
} | |
} | |
// calculate the start/end date of the bill that's being calculated | |
if ($lastChargeDate) { | |
$billingCycleStartDate = new DateTime($chargeDate->format('Y-m-d H:i:s')); | |
$billingCycleEndDate = new DateTime($chargeDate->format('Y-m-d H:i:s')); | |
if ($billingSchedule == "monthly") { | |
$billingCycleEndDate = $billingCycleEndDate->add(new DateInterval('P1M')); | |
} else { | |
$billingCycleEndDate = $billingCycleEndDate->add(new DateInterval("P1Y")); | |
} | |
} else { | |
$billingCycleStartDate = new DateTime(); | |
$billingCycleEndDate = new DateTime(); | |
$billingCycleEndDate->add(new DateInterval('P1M')); | |
} | |
$billingCycleStartDate = $billingCycleStartDate->format('Y-m-d H:i:s'); | |
$billingCycleEndDate = $billingCycleEndDate->format('Y-m-d H:i:s'); | |
// TODO: Get MAX LEADS instead ofnumLeads | |
$this->CI->load->model('companysummary_model'); | |
$this->companySummary = $this->CI->companysummary_model; | |
$summary = $this->companySummary->get($company['id']); | |
$this->companyChargeHistory->insert($company['id'], $paidByCompanyID, | |
$price, $company['companyName'], $clientPlan['schedule'], $clientPlan['price'], | |
$company['createTimestamp'], $billingCycleStartDate, $billingCycleEndDate, | |
$summary['numLeads'], $clientPlan['discount']); | |
$clientPlan['lastChargeDate'] = $chargeDate->format('Y-m-d H:i:s'); | |
// update company plan info including: | |
// an updated last charged date, an updated start date. | |
$this->companyPlanInfo->update($clientPlan['companyProfileID'], $clientPlan); | |
} | |
// only bill resellers on the first of the month | |
if (!$firstOfTheMonth && !$this->test_mode) { | |
// if it's not the first of the month, don't bill. | |
return; | |
} | |
foreach($resellerTotals as $resellerID => $total) { | |
$resellerPlanInfo = $this->resellerPlanInfo->get($resellerID); | |
// get their credits | |
$credits = $resellerPlanInfo['creditBalance']; | |
if ($credits >= $total) { | |
$credits -= $total; | |
} else { | |
$leftOver = $total - $credits; | |
$credits = 0; | |
$this->provider->chargeClient($resellerID, $leftOver); | |
} | |
$this->resellerPlanInfo->setCreditBalance($resellerID, $credits); | |
} | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment