public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     $configRange = new DateRange($config->start, $config->end);
     $eventRange = new DateRange($event->start, $event->end);
     if ($configRange->isEmpty()) {
         return $entries;
     }
     $amountPerRange = new Money($config->amount, $config->currency);
     $configDays = (int) $configRange->getStart()->diff($configRange->getEnd())->format('%R%a') + 1;
     $totalDays = (int) $eventRange->getStart()->diff($eventRange->getEnd())->format('%R%a') + 1;
     // If we match up nicely, just bill at the fixed value and we're done
     if ($eventRange->equals($configRange)) {
         $rangeTotal = $amountPerRange;
         $entry = new Entry();
         $entry->amount = $rangeTotal->round(2);
         $entry->currency = $rangeTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s for the entire range', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $totalDays, $totalDays == 1 ? 'day' : 'days', $amountPerRange->format());
         $entries->add($entry);
     } else {
         // (amount per fixed range / days in fixed range) * days billed
         $proratedTotal = $amountPerRange->div($configDays)->mul($totalDays);
         $entry = new Entry();
         $entry->amount = $proratedTotal->round(2);
         $entry->currency = $proratedTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s for part of %s to %s (%s %s) (prorated daily)', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $totalDays, $totalDays == 1 ? 'day' : 'days', $amountPerRange->format(), $configRange->getStart()->format('Y-m-d'), $configRange->getEnd()->format('Y-m-d'), $configDays, $configDays == 1 ? 'day' : 'days');
         $entries->add($entry);
     }
     return $entries;
 }
Example #2
0
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     // Days: Day difference + 1
     $days = (int) $event->start->diff($event->end)->format('%R%a') + 1;
     $amountPerDay = new Money($config->amount, $config->currency);
     // Safely calculate daily amount
     // amountPerDay * number of days
     $total = $amountPerDay->mul($days);
     $entry = new Entry();
     $entry->amount = $total->round(2);
     $entry->currency = $total->getCurrency();
     $entry->code = $config->code;
     $entry->description = sprintf('%s to %s (%s %s) @ %s per day', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $days, $days === 1 ? 'day' : 'days', $amountPerDay->format());
     $entries->add($entry);
     return $entries;
 }
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     // Nights: Day difference
     $nights = (int) $event->start->diff($event->end)->format('%R%a');
     // Nothing to do.
     if ($nights <= 0) {
         return $entries;
     }
     $amountPerNight = new Money($config->amount, $config->currency);
     // Safely calculate nightly amount
     // amountPerNight * number of nights
     $total = $amountPerNight->mul($nights);
     $entry = new Entry();
     $entry->amount = $total->round(2);
     $entry->currency = $total->getCurrency();
     $entry->code = $config->code;
     $entry->description = sprintf('%s to %s (%s %s) @ %s per night', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $nights, $nights === 1 ? 'night' : 'nights', $amountPerNight->format());
     $entries->add($entry);
     return $entries;
 }
Example #4
0
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     $eventRange = new DateRange($event->start, $event->end);
     // Days: Day difference + 1
     $totalDays = (int) $eventRange->getStart()->diff($eventRange->getEnd())->format('%R%a') + 1;
     // The total number of full weeks
     $weeks = (int) floor($totalDays / 7);
     // The number of leftover days after full weeks are counted
     $leftoverDays = (int) $totalDays % 7;
     $amountPerWeek = new Money($config->amount, $config->currency);
     // amount per week * number of weeks
     $weekTotal = $amountPerWeek->mul($weeks);
     // (amount per week / 7) * leftover days (prorate)
     $leftoverDayTotal = $amountPerWeek->div(7)->mul($leftoverDays);
     // If we have solid weeks, make an entry for that total
     if ($weeks > 0) {
         $fullWeekEndDate = clone $eventRange->getEnd();
         $fullWeekEndDate->modify("-{$leftoverDays} day");
         $entry = new entry();
         $entry->amount = $weekTotal->round(2);
         $entry->currency = $weekTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per week', $eventRange->getStart()->format('Y-m-d'), $fullWeekEndDate->format('Y-m-d'), $weeks, $weeks == 1 ? 'week' : 'weeks', $amountPerWeek->format());
         $entries->add($entry);
     }
     if ($leftoverDays > 0) {
         // Start 1 day after the end of the previous full week(s), if there
         // were any
         $partialWeekStartDate = clone $eventRange->getEnd();
         $partialWeekStartDate->modify("-{$leftoverDays} day")->modify('+1 day');
         $entry = new Entry();
         $entry->amount = $leftoverDayTotal->round(2);
         $entry->currency = $leftoverDayTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per week (prorated daily)', $partialWeekStartDate->format('Y-m-d'), $eventRange->getEnd()->format('Y-m-d'), $leftoverDays, $leftoverDays == 1 ? 'day' : 'days', $amountPerWeek->format());
         $entries->add($entry);
     }
     return $entries;
 }
Example #5
0
 /**
  * Asserts the validity of a given value and converts it to a Money object
  *
  * @param  mixed                    $money
  * @return Money
  * @throws InvalidArgumentException if a value is not valid money
  */
 protected function assertAndConvertValidMoney($money)
 {
     if (is_numeric($money)) {
         $money = new Money($money, $this->getCurrency(), $this->getScale());
     } else {
         if (!$money instanceof Money) {
             throw new InvalidArgumentException('Value must be either numeric or an instance of Money');
         }
     }
     if ($this->getCurrency() !== $money->getCurrency()) {
         throw new InvalidArgumentException('Value must be of the same currency as ' . $this->getCurrency());
     }
     return $money;
 }
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     // Create a pointer because we’re about to get procedural
     $pointer = clone $event->start;
     // If we don't start on the first of the month, we will need to
     // calculate "leading" days before the first full month (if there is
     // one).
     $leadingDays = 0;
     $leadingDaysInMonth = 0;
     if ($pointer->format('j') != 1) {
         $leadingStartAudit = $pointer->format('Y-m-d');
         $leadingEnd = min($event->end, new DateTime($pointer->format('Y-m-t')));
         $leadingEndAudit = $leadingEnd->format('Y-m-d');
         $leadingDaysInMonth = (int) $pointer->format('t');
         $leadingDays = (int) $pointer->diff($leadingEnd)->format('%R%a') + 1;
         $pointer->modify("+{$leadingDays} days");
     }
     // Initial number of full months
     $months = 0;
     // Get the date of the last day in the month our pointer is in
     $endOfMonth = new DateTime($pointer->format('Y-m-t'));
     $fullMonthStartAudit = $pointer->format('F Y');
     // If the pointer points at the first, and the end date is at or at or
     // beyond the end of the current month, we can count a full month.
     while ($pointer->format('j') == 1 && $event->end >= $endOfMonth) {
         $fullMonthEndAudit = $endOfMonth->format('F Y');
         $months += 1;
         // Now that we counted a full month, advance pointer 1 day past the
         // end of the month, which should be the first day of the next month
         $pointer = clone $endOfMonth;
         $pointer->modify('+1 day');
         // Update the new end of the month based on the new pointer value
         $endOfMonth = new DateTime($pointer->format('Y-m-t'));
     }
     $trailingDays = 0;
     $trailingDaysInMonth = 0;
     if ($pointer <= $event->end) {
         $trailingStartAudit = $pointer->format('Y-m-d');
         $trailingEndAudit = $event->end->format('Y-m-d');
         $trailingDaysInMonth = (int) $pointer->format('t');
         // Our pointer should be exactly where it needs to be to calculate any
         // "trailing" days
         $trailingDays = (int) $pointer->diff($event->end)->format('%R%a') + 1;
     }
     $amountPerMonth = new Money($config->amount, $config->currency);
     // amount per month * number of months
     $monthTotal = $amountPerMonth->mul($months);
     if ($leadingDays > 0) {
         // (amount per month / number of days in month) * leftover days (prorate)
         $leadingDayTotal = $amountPerMonth->div($leadingDaysInMonth)->mul($leadingDays);
         $entry = new Entry();
         $entry->amount = $leadingDayTotal->round(2);
         $entry->currency = $leadingDayTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per month (prorated daily)', $leadingStartAudit, $leadingEndAudit, $leadingDays, $leadingDays == 1 ? 'day' : 'days', $amountPerMonth->format());
         $entries->add($entry);
     }
     // If we have solid months, make an entry for that total
     if ($months > 0) {
         $entry = new Entry();
         $entry->amount = $monthTotal->round(2);
         $entry->currency = $monthTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s (%s %s) @ %s per month', $months == 1 ? $fullMonthStartAudit : "{$fullMonthStartAudit} to {$fullMonthEndAudit}", $months, $months == 1 ? 'month' : 'months', $amountPerMonth->format());
         $entries->add($entry);
     }
     if ($trailingDays > 0) {
         // (amount per month / number of days in month) * leftover days (prorate)
         $trailingDayTotal = $amountPerMonth->div($trailingDaysInMonth)->mul($trailingDays);
         $entry = new Entry();
         $entry->amount = $trailingDayTotal->round(2);
         $entry->currency = $trailingDayTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per month (prorated daily)', $trailingStartAudit, $trailingEndAudit, $trailingDays, $trailingDays == 1 ? 'day' : 'days', $amountPerMonth->format());
         $entries->add($entry);
     }
     return $entries;
 }
 /**
  * Format a currency amount according to the specified locale.
  *
  * @param $value float Value to format
  * @return string
  */
 public function formatCurrency($amount, $currency = 'USD')
 {
     $money = new Money($amount, $currency);
     return $money->format();
 }
Example #8
0
 public function testPositiveFormatEURInEnUs()
 {
     $m = new Money(1077.701, 'EUR');
     $m->setFormatter(new NumberFormatter('en-US', NumberFormatter::CURRENCY));
     $this->assertSame('€1,077.70', $m->format());
 }