Lavoro in PHP e costruisco un sistema di gestione delle sottoscrizioni da zero.
Sto cercando di capire le funzioni richieste per l'interfaccia di sottoscrizione (OOP) che devono essere implementate da classi che manterranno traccia del tipo di abbonamento, del prezzo, delle date di inizio / fine della fatturazione cicli, giorno di fatturazione del mese, data di inizio della sottoscrizione, numero di cicli a pagamento, ecc.
Requisiti e amp; Scopo: l'intero sistema verrà interrogato ogni giorno per verificare se ogni abbonamento deve essere fatturato o fatturato nuovamente se non è stato superato in precedenza.
Qual è un buon modo per farlo? È quello che ho finora ok?
Concettualmente, ho pensato a quanto segue, ma non sono sicuro se sto andando nella giusta direzione:
/*** Run this daily ***/
// Retrieve from DB
$subscription = new Subscription_Magazine('SUBSCRIPTION_ID');
// Call a utils function
if (SubscriptionUtils::isPaymentNeeded($subscription))
{
// Bill one cycle
SubscriptionUtils::charge($subscription, $subscription->getPaymentMethod(), 1);
}
/*** Utils to handle logic ***/
class SubscriptionUtils
{
const RETRY_ONLY_AFTER = "+1 day";
public static function isPaymentNeeded($subscription)
{
// Check if neither active nor past due
if (!$subscription->isActive() && !$subscription->isPastDue())
{
// Expired or canceled
return false;
}
// Check for recurring
if (!$subscription->isRecurring())
{
return false;
}
/* ? ? ? | | | | | | | ? ? ? */
/* ? ? ? \|/ \|/ \|/ \|/ \|/ \|/ \|/ ? ? ? */
/* ? ? ? V V V V V V V ? ? ? */
// Get subscribe date, cycles paid count, and length of cycle
$regDate = $subscription->getSubscriptionStartDate(); //unix timestamp
$cyclesPaid = $subscription->getPaidCyclesCount(); //int
$cycleLength = $subscription->getCycleLength(); //"+1 month" / "+6 months" / "+1 year"
// Check if paid through date is more than one month from now
$paidThroughDate = self::modifyTimestamp($regDate, $cycleLength, $cyclesPaid);
$oneCycleFromNow = self::modifyTimestamp(time(), $cycleLength);
if ($paidThroughDate > $oneCycleFromNow)
{
return false;
}
// Check if we are on or passed the billing date
$currentDay = date("j"); //int 1-31
$billingDay = $subscription->getBillingDayOfMonth(); //int 1-31
$daysInMonth = date("t"); //int 28-31
// Use valid day
$thisBillingDay = $billingDay > $daysInMonth ? $daysInMonth : $billingDay;
if ($thisBillingDay < $billingDay)
{
return false;
}
// Check if we already tried recently
$transaction = $subscriptions->getLastTransaction();
if ($transaction instanceof Transaction && time() < modifyTimestamp($transaction->date(), self::RETRY_ONLY_AFTER))
{
return false;
}
//yes, return true that we need to charge now
return true;
/* ? ? ? ^ ^ ^ ^ ^ ^ ^ ? ? ? */
/* ? ? ? /|\ /|\ /|\ /|\ /|\ /|\ /|\ ? ? ? */
/* ? ? ? | | | | | | | ? ? ? */
}
public static function charge(Subscription $subscription, PaymentMethod $paymentMethod, $cyclesToCharge)
{
$transaction = new Transaction();
$transaction->add("One Month Magazine", $subscription->getPrice(), $cyclesToCharge);
$transaction->pay($paymentMethod);
$subscription->addTransaction($transaction);
if (!$transaction->success())
{
return false;
}
$subscription->paidCycleIncrement($cyclesToCharge);
return true;
}
public static function modifyTimestamp($timestamp, $modifyText, $repeatNum = 1)
{
//Trivia code
//Note: dates don't rollover.
//For example: if "+1 month", then January 31st will result in February 28th (or 29th)
}
//...other stuff too
}