PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/s5-members/application/default/models/ProductUpgrade.php

https://bitbucket.org/awylie199/s5t
PHP | 237 lines | 164 code | 17 blank | 56 comment | 24 complexity | 474cc792cfe511ebc41e3a1924939102 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0, LGPL-3.0, MIT, BSD-3-Clause
  1. <?php
  2. /**
  3. * Class represents records from table product_upgrade
  4. * {autogenerated}
  5. * @property int $product_upgrade_id
  6. * @property int $from_billing_plan_id
  7. * @property int $to_billing_plan_id
  8. * @property double $surcharge
  9. * @see Am_Table
  10. */
  11. class ProductUpgrade extends Am_Record
  12. {
  13. const TYPE_DEFAULT = 'default';
  14. const TYPE_FLAT = 'flat';
  15. /** @return BillingPlan */
  16. function getFromPlan()
  17. {
  18. return $this->getDi()->billingPlanTable->load($this->from_billing_plan_id, false);
  19. }
  20. /** @return BillingPlan */
  21. function getToPlan()
  22. {
  23. return $this->getDi()->billingPlanTable->load($this->to_billing_plan_id, false);
  24. }
  25. /** @return Product */
  26. function getFromProduct()
  27. {
  28. $pr = $this->getDi()->productTable->load($this->getFromPlan()->product_id);
  29. return $pr;
  30. }
  31. /** @return Product */
  32. function getToProduct()
  33. {
  34. $pr = $this->getDi()->productTable->load($this->getToPlan()->product_id);
  35. return $pr;
  36. }
  37. /**
  38. * Calculate first payment for upgraded/downgraded subscription
  39. * calculated move from $item -> $to billling plan
  40. * @return Invoice
  41. */
  42. function createUpgradeInvoice(Invoice $exInvoice, InvoiceItem $item, $coupon = false)
  43. {
  44. $row = array(
  45. 'user_id' => $exInvoice->user_id,
  46. 'paysys_id' => $exInvoice->paysys_id,
  47. 'currency' => $exInvoice->currency,
  48. 'tax_type' => $exInvoice->tax_rate,
  49. 'tax_rate' => $exInvoice->tax_type,
  50. 'tax_title' => $exInvoice->tax_title,
  51. 'is_confirmed' => 1,
  52. 'discount_first' => 0.0,
  53. 'discount_second' => 0.0
  54. );
  55. $invoice = $this->getDi()->invoiceTable->createRecord($row);
  56. $to = $this->getToPlan();
  57. if (!$to)
  58. throw new Am_Exception_Configuration("Upgrade: cannot load [to] plan {$this->to_billing_plan_id}");
  59. $pr = $to->getProduct();
  60. if (!$pr)
  61. throw new Am_Exception_Configuration("Upgrade: cannot load [to] product {$to->product_id}");
  62. $invoice->add($pr, $item->qty);
  63. $newItem = $invoice->getItem(0);
  64. /* @var $newItem InvoiceItem */
  65. $invoice->data()->set(Invoice::UPGRADE_INVOICE_ID, $exInvoice->pk());
  66. $invoice->data()->set(Invoice::UPGRADE_INVOICE_ITEM_ID, $item->pk());
  67. if ($coupon)
  68. {
  69. $invoice->setCouponCode($coupon);
  70. $invoice->validateCoupon();
  71. }
  72. $invoice->calculate();
  73. // now calculate discounts and surcharges
  74. $unusedAmount = $this->getUnusedAmount($exInvoice, $item);
  75. $newItem->data()->set('orig_first_price', null);
  76. if($this->type == self::TYPE_FLAT)
  77. {
  78. $newItem->first_price = $this->surcharge;
  79. }
  80. else
  81. {
  82. $unusedAmount = $this->getUnusedAmount($exInvoice, $item);
  83. // magic upgrade formula!
  84. $newItem->first_price = moneyRound(
  85. $newItem->first_price
  86. - $unusedAmount
  87. + $this->surcharge);
  88. }
  89. if ($newItem->first_price < 0)
  90. {
  91. $invoice->data()->set(Invoice::UPGRADE_REFUND, moneyRound($unusedAmount + $newItem->first_price));
  92. $newItem->first_price = 0.0;
  93. }
  94. $invoice->calculate();
  95. $this->getDi()->hook->call(Am_Event::BEFORE_PRODUCT_UPGRADE, array(
  96. 'invoice' => $invoice,
  97. 'exItem' => $item,
  98. 'exInvoice' => $exInvoice,
  99. 'upgrade' => $this,
  100. ));
  101. return $invoice;
  102. }
  103. function addProrateDays()
  104. {
  105. throw new Am_Exception_NotImplemented(__METHOD__);
  106. /* // prorate code
  107. if ($daysPaid)
  108. {
  109. $k = $this->compareDayCost($item, $newItem);
  110. $daysPaid = intval($daysPaid * $k); // recalculate to new billing plan
  111. $p = new Am_Period($newItem->first_period);
  112. $date = $p->addTo('now');
  113. $p = new Am_Period("{$daysPaid}d");
  114. $date = $p->addTo($date);
  115. $days_diff = intval((strtotime($date . ' 00:00:00') - strtotime('today 00:00:00')) / (3600*24));
  116. $newItem->first_period = "{$days_diff}d";
  117. $invoice->first_period = "{$days_diff}d";
  118. }*/
  119. }
  120. /**
  121. * Return unused amount for $item subscription
  122. * null will be returned if:
  123. * - subscription is lifetime
  124. * - subscription is for free product
  125. * - subscription is expired
  126. * @param Invoice $invoice
  127. * @param InvoiceItem $item
  128. * @return float|null
  129. */
  130. function getUnusedAmount(Invoice $invoice, InvoiceItem $item)
  131. {
  132. $row = $this->getDi()->db->selectRow("
  133. SELECT begin_date, expire_date
  134. FROM ?_access
  135. WHERE invoice_id=?d AND product_id=?
  136. ORDER by expire_date desc LIMIT 1
  137. ",
  138. $invoice->pk(), $item->item_id);
  139. if (!$row) return;
  140. $maxExpire = $row['expire_date'];
  141. $maxBegin = $row['begin_date'];
  142. if ($maxExpire < $this->getDi()->sqlDate)
  143. return null;
  144. if ($maxExpire == Am_Period::MAX_SQL_DATE)
  145. return null;
  146. $daysTotal = $this->diffDays($maxBegin, $maxExpire);
  147. $daysUnused = $this->diffDays($this->getDi()->sqlDate, $maxExpire) - 1 ;// -1 as today date can be fully used
  148. $pc = $invoice->getPaymentsCount();
  149. $field = ($pc == 1 && (float)$invoice->first_total) || ($pc == 0)
  150. ? 'first_total' : 'second_total';
  151. $paid = $item->get($field);
  152. return moneyRound($daysUnused * $paid / $daysTotal);
  153. }
  154. function diffDays($date1, $date2)
  155. {
  156. return round((strtotime("$date2 12:00:00")
  157. - strtotime("$date1 12:00:00")) / 86400);
  158. }
  159. /**
  160. * @param InvoiceItem $old
  161. * @param InvoiceItem $new
  162. * @return float old_price / new_price
  163. */
  164. function compareDayCost(InvoiceItem $old, InvoiceItem $new)
  165. {
  166. // calculate difference in money
  167. // if both products have second_period we can compare prices
  168. $k = 1.0;
  169. foreach (array('second_', 'first_') as $k)
  170. {
  171. $period_o = $old->get($k.'period');
  172. $period_n = $new->get($k.'period');
  173. $price_o = (float)$old->get($k.'price');
  174. $price_n = (float)$new->get($k.'price');
  175. if (!$price_n || !$price_o || !$period_o || !$period_n) continue;
  176. if ($period_o == $period_n)
  177. return round($price_o / $price_n, 4);
  178. // else we need to recalculate both periods to days
  179. $po = new Am_Period($period_o);
  180. $pn = new Am_Period($period_n);
  181. $days_o = strtotime($po->addTo('2012-04-01') . ' 00:00:00')
  182. - strtotime('2012-04-01 00:00:00');
  183. $days_o = intval($days_o/(3600*24));
  184. $days_n = strtotime($pn->addTo('2012-04-01') . ' 00:00:00')
  185. - strtotime('2012-04-01 00:00:00');
  186. $days_n = intval($days_n/(3600*24));
  187. $price_o /= $days_o;
  188. $price_n /= $days_n;
  189. return round($price_o / $price_n, 4);
  190. }
  191. }
  192. }
  193. class ProductUpgradeTable extends Am_Table
  194. {
  195. protected $_key = 'product_upgrade_id';
  196. protected $_table = '?_product_upgrade';
  197. protected $_ucache = array();
  198. /**
  199. * @param Invoice $invoice
  200. * @return array of ProductUpgrade
  201. */
  202. function findUpgrades(Invoice $invoice, InvoiceItem $item)
  203. {
  204. if (empty($this->_ucache))
  205. {
  206. foreach ($this->_db->select("SELECT * FROM {$this->_table}") as $row)
  207. $this->_ucache[ $row['from_billing_plan_id'] ][] = $row;
  208. }
  209. $ret = array();
  210. if(!array_key_exists($item->billing_plan_id, $this->_ucache)) return $ret;
  211. foreach ($this->_ucache[ $item->billing_plan_id ] as & $row)
  212. {
  213. if (empty($row['_obj']))
  214. $row['_obj'] = $this->createRecord($row);
  215. if ($invoice->canUpgrade($item, $row['_obj']))
  216. $ret[] = $row['_obj'];
  217. }
  218. return $ret;
  219. }
  220. }