/**
 * Calculates the number of days between first and second parameter
 *
 * @param  int Date 1
 * @param  int Date 2
 * @return int Number of days
 *
 * @author Former03 GmbH :: Florian Lippert <*****@*****.**>
 */
function calculateDayDifference($begin, $end)
{
    $daycount = 0;
    $begin = transferDateToArray($begin);
    $end = transferDateToArray($end);
    $direction = 1;
    // Sanity check, if our given array is in the right format
    if (checkDateArray($begin) === true && checkDateArray($end) === true) {
        if (strtotime($end['y'] . '-' . $end['m'] . '-' . $end['d']) < strtotime($begin['y'] . '-' . $begin['m'] . '-' . $begin['d'])) {
            $tmp = $end;
            $end = $begin;
            $begin = $tmp;
            unset($tmp);
            $direction = -1;
        }
        $yeardiff = (int) $end['y'] - (int) $begin['y'];
        $monthdiff = (int) $end['m'] + 12 * $yeardiff - (int) $begin['m'];
        for ($i = 0; $i < abs($monthdiff); $i++) {
            $daycount += getDaysForMonth($begin['m'] + $i, $begin['y']);
        }
        $daycount += $end['d'] - $begin['d'];
        $daycount *= $direction;
    }
    return $daycount;
}
Beispiel #2
0
 /**
  * This method is a wrapper for parent::collect. Before launching it,
  * we will gather information about traffic usage for all given userids.
  *
  * @param bool   Should we fix invoice (means we call self::setLastInvoiced to latest invoiced date).
  * @param bool   Should we include the setup fee?
  * @param bool   Should we include the interval fees?
  * @return array All invoice rows
  *
  * @author Former03 GmbH :: Florian Lippert <*****@*****.**>
  */
 function collect($fixInvoice = false, $include_setup_fee = false, $include_interval_fee = false)
 {
     $traffic_result = $this->db->query('SELECT `' . getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key') . '`, `year`, `month`, `day`, SUM(`http`+`ftp_down`+`ftp_up`+`mail`) as traffic FROM `' . getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'table') . '` WHERE `' . getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key') . '` IN ( ' . implode(', ', $this->userIds) . ' ) GROUP BY `' . getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key') . '`, `year`, `month`, `day`');
     while ($traffic_row = $this->db->fetch_array($traffic_result)) {
         if (!isset($this->traffic_data[$traffic_row[getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key')]]) || !is_array($this->traffic_data[$traffic_row[getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key')]])) {
             $this->traffic_data[$traffic_row[getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key')]] = array();
         }
         $date = $traffic_row['year'] . '-' . $traffic_row['month'] . '-' . $traffic_row['day'];
         if (!isset($this->traffic_data[$traffic_row[getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key')]][$date]) && checkDateArray(transferDateToArray($date))) {
             $this->traffic_data[$traffic_row[getModeDetails($this->mode, 'TABLE_PANEL_TRAFFIC', 'key')]][$date] = (int) $traffic_row['traffic'];
         }
     }
     reset($this->userIds);
     foreach ($this->userIds as $userId) {
         // Using fixed values here, because those settings are always the same. interval_fee will be calculated lateron, when traffic consumption is calculated
         $this->service_details[$userId]['service_active'] = '1';
         $this->service_details[$userId]['interval_fee'] = '0.00';
         $this->service_details[$userId]['interval_length'] = '1';
         $this->service_details[$userId]['interval_type'] = 'm';
         $this->service_details[$userId]['interval_payment'] = '1';
         // Always postpaid, we can't invoice this month/payment_term's traffic, if it hasn't finished yet
         $this->service_details[$userId]['setup_fee'] = '0.00';
         $this->service_details[$userId]['payment_every'] = '1';
         $this->service_details[$userId]['lastinvoiced_date'] = $this->service_details[$userId]['lastinvoiced_date_traffic'];
         // We still want to be able to calculate traffic usage in case of no service information
         if (($this->service_details[$userId]['lastinvoiced_date'] == '0' || $this->service_details[$userId]['lastinvoiced_date'] == '') && ($this->service_details[$userId]['servicestart_date'] == '0' || $this->service_details[$userId]['servicestart_date'] == '') && isset($this->traffic_data[$userId]) && is_array($this->traffic_data[$userId]) && !empty($this->traffic_data[$userId])) {
             // Get the date of first appereance of traffic
             ksort($this->traffic_data[$userId]);
             $dates = array_keys($this->traffic_data[$userId]);
             $this->service_details[$userId]['servicestart_date'] = $dates[0];
         }
     }
     return parent::collect($fixInvoice, $include_setup_fee, $include_interval_fee);
 }
/**
 * Manipulates a date, like adding a month or so and correcting it afterwards
 * (2008-01-33 -> 2008-02-02)
 *
 * @param  array  The date array
 * @param  string The operation, may be '+', 'add', 'sum' or '-', 'subtract', 'subduct'
 * @param  int    Number if days/month/years
 * @param  string Either 'y', 'm', 'd', depending on what part to change.
 * @param  array  A valid date array with original date, mandatory for more than one manipulation on same date.
 * @return date   The manipulated date array
 *
 * @author Former03 GmbH :: Florian Lippert <*****@*****.**>
 */
function manipulateDate($date, $operation, $count, $type, $original_date = null)
{
    $newdate = $date;
    $date = transferDateToArray($date);
    if (checkDateArray($date) === true && isset($date[$type])) {
        switch ($operation) {
            case '+':
            case 'add':
            case 'sum':
                $date[$type] += (int) $count;
                break;
            case '-':
            case 'subtract':
            case 'subduct':
                $date[$type] -= (int) $count;
                break;
        }
        if ($original_date !== null && ($original_date = transferDateToArray($original_date)) !== false && $type == 'm') {
            if ($original_date['d'] > getDaysForMonth($date['m'], $date['y'])) {
                $date['d'] = getDaysForMonth($date['m'], $date['y']) - (getDaysForMonth($original_date['m'], $original_date['y']) - $original_date['d']);
            } else {
                $date['d'] = $original_date['d'];
            }
        }
        while (checkDateArray($date) === false) {
            if ($date['d'] > getDaysForMonth($date['m'], $date['y'])) {
                $date['d'] -= getDaysForMonth($date['m'], $date['y']);
                $date['m']++;
            }
            if ($date['d'] < 1) {
                $date['m']--;
                $date['d'] += getDaysForMonth($date['m'], $date['y']);
                // Adding here, because date[d] is negative
            }
            if ($date['m'] > 12) {
                $date['m'] -= 12;
                $date['y']++;
            }
            if ($date['m'] < 1) {
                $date['y']--;
                $date['m'] += 12;
            }
        }
        $newdate = $date['y'] . '-' . $date['m'] . '-' . $date['d'];
    }
    return $newdate;
}
Beispiel #4
0
 /**
  * This method adds taxrates to the invoice rows.
  *
  * @param array  The array containing all invoice rows
  *
  * @return array The array containing (taxed) invoice rows
  *
  * @author Former03 GmbH :: Florian Lippert <*****@*****.**>
  */
 public function applyTaxRate($invoice)
 {
     $invoice_new = array();
     foreach ($invoice as $rowid => $invoice_row) {
         // If we don't have a valid taxclass, use the default one.
         if (!isset($invoice_row['taxclass']) || !isset($this->taxclasses[$invoice_row['taxclass']])) {
             $invoice_row['taxclass'] = $this->default_taxclass;
         }
         if (isset($invoice_row['taxclass']) && isset($this->taxclasses[$invoice_row['taxclass']])) {
             // Once-fees are quite easy, just get the valid taxrate and add it to the row.
             if (isset($invoice_row['service_occurence']) && $invoice_row['service_occurence'] == 'once') {
                 $taxchanges = $this->getTaxChanges($invoice_row['taxclass'], $invoice_row['service_date']);
                 $pricing = array('taxrate' => $taxchanges[0]['taxrate'], 'total_fee' => $invoice_row['setup_fee']);
                 $invoice_new[] = array_merge($invoice_row, $pricing);
             } elseif (isset($invoice_row['service_occurence']) && $invoice_row['service_occurence'] == 'period') {
                 // Get all tax changes in our service interval
                 $taxchanges = $this->getTaxChanges($invoice_row['taxclass'], $invoice_row['service_date_begin'], manipulateDate($invoice_row['service_date_end'], '-', 1, 'd'));
                 // In pricing we store all changes to our invoice row, will get merged lateron.
                 $pricing = array('taxrate' => $taxchanges[0]['taxrate'], 'total_fee' => 0);
                 // number_days will store the days we already processed...
                 $number_days = 0;
                 // ... whereas days_diff contains the whole number of days of our service interval.
                 $days_diff = calculateDayDifference($invoice_row['service_date_begin'], $invoice_row['service_date_end']);
                 $service_date_begin_array = transferDateToArray($invoice_row['service_date_begin']);
                 // Now we walk through the interval, stepping is the interval length.
                 while ($days_diff >= $number_days + $this->getDaysForInterval($invoice_row['interval_length'], $invoice_row['interval_type'], $service_date_begin_array)) {
                     // Whenever we happen to meet a tax change, remaining will reduced by the number of days to that tax change.
                     $remaining = $interval_days = $this->getDaysForInterval($invoice_row['interval_length'], $invoice_row['interval_type'], $service_date_begin_array);
                     $interval_begin = manipulateDate($invoice_row['service_date_begin'], '+', $number_days, 'd');
                     $interval_end = manipulateDate($invoice_row['service_date_begin'], '+', $number_days + $interval_days, 'd');
                     // Now get tax changes in the current interval.
                     $taxchanges = $this->getTaxChanges($invoice_row['taxclass'], $interval_begin, $interval_end);
                     // Maybe taxrate already changed on the first day of our interval.
                     if ($pricing['taxrate'] != $taxchanges[0]['taxrate']) {
                         $pricing['service_date_end'] = $taxchanges[0]['valid_to'];
                         $invoice_new[] = array_merge($invoice_row, $pricing);
                         $pricing['taxrate'] = $taxchanges[0]['taxrate'];
                         $pricing['total_fee'] = 0;
                     }
                     // Anyways, we don't need the current taxrate.
                     unset($taxchanges[0]);
                     // Walk through all taxchanges...
                     foreach ($taxchanges as $valid_from => $taxchange) {
                         $tax_days = calculateDayDifference($interval_begin, $valid_from);
                         // Subtract the days we are going to tax from the remaining days in our interval
                         $remaining -= $tax_days;
                         // total_fee is a fraction of the interval fee
                         $pricing['total_fee'] += $invoice_row['interval_fee'] * ($tax_days / $interval_days);
                         // Set ending day of row to day when tax changed
                         $pricing['service_date_end'] = $taxchange['valid_from'];
                         // And add a new row to invoice
                         $invoice_new[] = array_merge($invoice_row, $pricing);
                         // Next line begins with the day when tax changed
                         $interval_begin = $pricing['service_date_begin'] = $taxchange['valid_from'];
                         $pricing['taxrate'] = $taxchange['taxrate'];
                         $pricing['total_fee'] = 0;
                     }
                     // Incruse number_days (loop condition value)
                     $number_days += $interval_days;
                     // also update service_date_begin_array, so self::getDaysForInterval returns a correct value in our loop condition
                     $service_date_begin_array[$invoice_row['interval_type']] += $invoice_row['interval_length'];
                     // Finally add the remaining fraction to total_fee
                     $pricing['total_fee'] += $invoice_row['interval_fee'] * ($remaining / $interval_days);
                 }
                 // Last element, so use our real service_date_end
                 unset($pricing['service_date_end']);
                 // If there are still have some days left (e.g. when service was terminated during an interval)...
                 if ($days_diff > $number_days) {
                     // ... calculate last total_fee...
                     $pricing['total_fee'] += $invoice_row['interval_fee'] * (($days_diff - $number_days) / $this->getDaysForInterval($invoice_row['interval_length'], $invoice_row['interval_type'], $service_date_begin_array));
                 }
                 // ... and finally add last line.
                 $invoice_new[] = array_merge($invoice_row, $pricing);
             }
         } else {
             $invoice_new[] = $invoice_row;
         }
     }
     return $invoice_new;
 }
Beispiel #5
0
 /**
  * This method collects the invoice rows.
  *
  * @param bool   Should we fix invoice (means we call self::setLastInvoiced to latest invoiced date).
  * @param bool   Should we include the setup fee?
  * @param bool   Should we include the interval fees?
  *
  * @return array All invoice rows
  *
  * @author Former03 GmbH :: Florian Lippert <*****@*****.**>
  */
 public function collect($fixInvoice = false, $include_setup_fee = false, $include_interval_fee = false)
 {
     $invoice = array();
     reset($this->service_details);
     foreach ($this->service_details as $serviceId => $service_detail) {
         if (checkDateArray(transferDateToArray($service_detail['servicestart_date'])) === true) {
             // Load template which is valid through our setup date
             $template = $this->findValidTemplate($service_detail['servicestart_date'], $this->selectAppropriateTemplateKey($service_detail));
             foreach ($this->defaultvalues as $field => $value) {
                 // We are using $this->service_details[$serviceId] instead of $service_detail so we can see the original values, as the "working copy" ($service_detail) could have been changed...
                 if ((!isset($this->service_details[$serviceId][$field]) || isset($this->service_details[$serviceId][$field]) && $this->service_details[$serviceId][$field] == $value) && isset($template[$field]) && $template[$field] != $value) {
                     $service_detail[$field] = $template[$field];
                 }
             }
             // If quantity is not set, we do need a value 1, otherwise this doesn't make sense...
             if (!isset($service_detail['quantity'])) {
                 $service_detail['quantity'] = 1;
             }
             // Add setup fee to invoice
             if (checkDateArray(transferDateToArray($service_detail['lastinvoiced_date'])) !== true || $this->allowLastInvoicedDatePastServiceStart === false && calculateDayDifference($service_detail['lastinvoiced_date'], $service_detail['servicestart_date']) > 0) {
                 if ($include_setup_fee === true) {
                     $invoice[] = $this->buildInvoiceRowSetupFee($service_detail, $this->getServiceDescription($service_detail, 'setup'));
                 }
                 $service_detail['lastinvoiced_date'] = $service_detail['servicestart_date'];
             }
             // If payment_every is not set, we do need a value 1, otherwise nextinvoiced_date wouldn't be calculated correctly and we'll get stuck in an infinite loop
             if (!isset($service_detail['payment_every'])) {
                 $service_detail['payment_every'] = 1;
             }
             if ((int) $service_detail['interval_length'] != 0 && (int) $service_detail['payment_every'] != 0 && in_array($service_detail['interval_type'], getIntervalTypes('array'))) {
                 $original_date = $service_detail['lastinvoiced_date'];
                 $service_detail['nextinvoiced_date'] = manipulateDate($service_detail['lastinvoiced_date'], '+', (int) $service_detail['interval_length'] * (int) $service_detail['payment_every'], $service_detail['interval_type'], $original_date);
                 while ($service_detail['interval_payment'] == CONST_BILLING_INTERVALPAYMENT_PREPAID && calculateDayDifference($service_detail['lastinvoiced_date'], time()) >= 0 && !($service_detail['service_active'] == '0' && calculateDayDifference($service_detail['lastinvoiced_date'], $service_detail['serviceend_date']) <= 0) || $service_detail['interval_payment'] == CONST_BILLING_INTERVALPAYMENT_POSTPAID && (calculateDayDifference($service_detail['nextinvoiced_date'], time()) >= 0 || $this->endServiceImmediately === true && $service_detail['service_active'] == '0' && calculateDayDifference($service_detail['lastinvoiced_date'], $service_detail['serviceend_date']) > 0 && calculateDayDifference($service_detail['serviceend_date'], $service_detail['nextinvoiced_date']) >= 0 && calculateDayDifference($service_detail['lastinvoiced_date'], time()) >= 0 && calculateDayDifference($service_detail['serviceend_date'], time()) >= 0)) {
                     // Reload template which is valid through our current invoice period
                     reset($this->defaultvalues);
                     $template = $this->findValidTemplate($service_detail['lastinvoiced_date'], $this->selectAppropriateTemplateKey($service_detail));
                     foreach ($this->defaultvalues as $field => $value) {
                         // We are using $this->service_details[$serviceId] instead of $service_detail so we can see the original values, as the "working copy" ($service_detail) could have been changed...
                         if ((!isset($this->service_details[$serviceId][$field]) || isset($this->service_details[$serviceId][$field]) && $this->service_details[$serviceId][$field] == $value) && isset($template[$field]) && $template[$field] != $value) {
                             $service_detail[$field] = $template[$field];
                         }
                     }
                     if ($this->endServiceImmediately === true && $service_detail['service_active'] == '0' && calculateDayDifference($service_detail['lastinvoiced_date'], $service_detail['serviceend_date']) > 0 && calculateDayDifference($service_detail['serviceend_date'], $service_detail['nextinvoiced_date']) >= 0 && calculateDayDifference($service_detail['lastinvoiced_date'], time()) >= 0 && calculateDayDifference($service_detail['serviceend_date'], time()) >= 0) {
                         $service_detail['nextinvoiced_date'] = $service_detail['serviceend_date'];
                     }
                     // Sanity check, shouldn't be needed...
                     if (calculateDayDifference($service_detail['lastinvoiced_date'], $service_detail['nextinvoiced_date']) >= 0) {
                         $service_detail['service_date_begin'] = $service_detail['lastinvoiced_date'];
                         $service_detail['service_date_end'] = $service_detail['nextinvoiced_date'];
                         if ($include_interval_fee === true) {
                             $invoice[] = $this->buildInvoiceRowIntervalFee($service_detail, $this->getServiceDescription($service_detail, 'interval'));
                         }
                     }
                     // Go on in loop, set lastinvoiced_date to nextinvoiced_date ...
                     $service_detail['lastinvoiced_date'] = $service_detail['nextinvoiced_date'];
                     // ... and recalculate nextinvoiced_date.
                     $service_detail['nextinvoiced_date'] = manipulateDate($service_detail['lastinvoiced_date'], '+', (int) $service_detail['interval_length'] * (int) $service_detail['payment_every'], $service_detail['interval_type'], $original_date);
                 }
             }
             if ($fixInvoice === true) {
                 $this->setLastInvoiced($serviceId, $service_detail);
             }
         }
     }
     return $invoice;
 }