function service_periods_add($id_service_customer, $billing_mode) { log_debug("inc_services_invoicegen", "Executing service_periods_add({$id_service_customer}, {$billing_mode})"); /* Fetch required information from services_customers (service-customer assignment table) */ $sql_custserv_obj = new sql_query(); $sql_custserv_obj->string = "SELECT serviceid, date_period_first, date_period_next, date_period_last FROM services_customers WHERE id='{$id_service_customer}' LIMIT 1"; $sql_custserv_obj->execute(); $sql_custserv_obj->fetch_array(); $serviceid = $sql_custserv_obj->data[0]["serviceid"]; $date_period_start = $sql_custserv_obj->data[0]["date_period_next"]; $date_period_last = $sql_custserv_obj->data[0]["date_period_last"]; if (empty($date_period_last) || $date_period_last == "0000-00-00") { $date_period_last = NULL; } /* Has the service reached it's end date? */ if ($date_period_last) { /* Is deactivation required? */ if (time_date_to_timestamp($date_period_last) <= time()) { log_write("debug", "inc_services_invoicegen", "Service {$id_service_customer} has reached deactivation date ({$date_period_last}), disabling service."); // disable the service $obj_service = new customer_services(); $obj_service->id_service_customer = $id_service_customer; $obj_service->verify_id_service_customer(); $obj_service->service_disable(); unset($obj_service); } /* Have we reached the end of the service with the current period? */ if ($date_period_start == $date_period_last) { // start date the same as the last date log_write("debug", "inc_services_invoicegen", "Service {$id_service_customer} is due to be deactived on {$date_period_last}, new period due to start on {$date_period_start}, preventing new period generation and making no changes."); return 1; } /* Catch any glitches, where the period start date is newer than the period last date, and correct. */ if (time_date_to_timestamp($date_period_start) > time_date_to_timestamp($date_period_last)) { log_write("debug", "inc_services_invoicegen", "Service start date of {$date_period_start}, but last period date is for {$date_period_last} - adjusting start date to match last"); $date_period_start = $date_period_last; } } /* Handle new services If the service has not been billed before, the date_period_first value will have been set, but not the date_period_next value. */ if ($sql_custserv_obj->data[0]["date_period_next"] == "0000-00-00") { $date_period_start = $sql_custserv_obj->data[0]["date_period_first"]; } /* Fetch Dates */ $billing_cycle = sql_get_singlevalue("SELECT billing_cycles.name as value FROM services LEFT JOIN billing_cycles ON billing_cycles.id = services.billing_cycle WHERE services.id='{$serviceid}'"); $dates = service_period_dates_generate($date_period_start, $billing_cycle, $billing_mode); $date_period_start = $dates["start"]; $date_period_end = $dates["end"]; $date_period_next = $dates["next"]; /* Handle Last Date If the service has reached the date_period_last, we need to flag the period as being the last - this means if an end/last date is set half way during a period, the period will be changed into a partial period. */ if ($date_period_last) { if (time_date_to_timestamp($date_period_last) <= time_date_to_timestamp($date_period_end)) { /* Period ending date is later than the last period date - adjust the end date to align. */ $date_period_end = $date_period_last; $date_period_next = "0000-00-00"; } if ($date_period_last == $date_period_end) { /* Period end date same as the service last date. */ $date_period_next = "0000-00-00"; } } /* Calculate date to bill the period on */ switch ($billing_mode) { case "periodadvance": case "monthadvance": // PERIODADVANCE / MONTHADVANCE // // Billing date should be set to today, since the period will have just been generated in advance today and // we don't need to bother regenerating the billing period. // $date_period_billing = date("Y-m-d"); break; case "periodtelco": case "monthtelco": // PERIODTELCO / MONTHTELCO // // With Telco periods, we need to bill on the first day of the new period. $date_period_billing = $date_period_start; break; case "periodend": case "monthend": // PERIODEND / MONTHEND // // We can't bill for this period until it's end, so we set the billing date to the start of the next period, // so that the period has completely finished before we invoice. $date_period_billing = $date_period_next; break; } log_write("debug", "inc_customers", "Calculated billing date of \"" . $date_period_billing . "\" for service billing mode of \"" . $billing_mode . "\""); /* Start Transaction */ $sql_obj = new sql_query(); $sql_obj->trans_begin(); /* Add a new period */ $sql_obj->string = "INSERT INTO services_customers_periods (id_service_customer, date_start, date_end, date_billed) VALUES ('{$id_service_customer}', '{$date_period_start}', '{$date_period_end}', '{$date_period_billing}')"; $sql_obj->execute(); /* Update services_customers */ $sql_obj->string = "UPDATE services_customers SET date_period_next='{$date_period_next}' WHERE id='{$id_service_customer}' LIMIT 1"; $sql_obj->execute(); /* If the period is ending, we need to create a special 0-day period - this is used to account for usage on services, by having a final period with no service charge but with usage for the previous (final) period. */ if ($date_period_last && $date_period_next == "0000-00-00") { /* This period is for one day after the service terminates - it will force an invoice to be generated for the terminated service, with $0 plan charges and any usage charges that apply. Depending on configuration, the customer may or may not recieve a copy of the invoice. */ $sql_obj->string = "INSERT INTO services_customers_periods (id_service_customer, date_start, date_end, date_billed) VALUES ('{$id_service_customer}', DATE_ADD('{$date_period_end}', INTERVAL 1 DAY), DATE_ADD('{$date_period_end}', INTERVAL 1 DAY), DATE_ADD('{$date_period_billing}', INTERVAL 1 DAY))"; $sql_obj->execute(); } /* Commit */ if (error_check()) { $sql_obj->trans_rollback(); log_write("error", "process", "An error occured whilst attempting to add a new period to a service. No changes were made."); return 0; } else { $sql_obj->trans_commit(); } return 1; }
} } else { /* Adjust an existing service "*/ // enable/disable service if needed if ($obj_customer->service_get_status() != $data["active"]) { if ($data["active"]) { // service has been enabled $obj_customer->service_enable(); // generate service period - this won't invoice, but allows us to get a date // for when the invoice will be generated service_periods_generate($obj_customer->id); } else { // service has been disabled $obj_customer->service_disable(); } } // adjust dates if possible - only possible for services that have yet to be billed, any periods that currently // exist are uninvoiced and can be safely deleted. if ($data["date_period_first"]) { log_write("notification", "process", "Adjusted service start date to " . time_format_humandate($data["date_period_first"]) . ""); // handle service information $obj_sql = new sql_query(); $obj_sql->string = "UPDATE services_customers SET date_period_first='" . $data["date_period_first"] . "', date_period_next='" . $data["date_period_next"] . "' WHERE id='" . $obj_customer->id_service_customer . "' LIMIT 1"; $obj_sql->execute(); unset($obj_sql); // delete service periods $obj_sql = new sql_query(); $obj_sql->string = "DELETE FROM services_customers_periods WHERE id_service_customer='" . $obj_customer->id_service_customer . "'"; $obj_sql->execute();