'datetime:H:i', 'offpeak_end' => 'datetime:H:i', ]; protected $table = 'supplier_broadband'; // Map the table fields, with the extra fields public const traffic_map = [ 'base_up_offpeak' => 'extra_up_offpeak', 'base_down_offpeak' => 'extra_down_offpeak', 'base_up_peak' => 'extra_up_peak', 'base_down_peak' => 'extra_down_peak', ]; // Map the NULL relationships - and where traffic gets applied if NULL public const traffic_merge = [ 'extra_up_offpeak' => 'base_down_offpeak', 'extra_down_offpeak' => 'base_down_peak', 'extra_up_peak' => 'base_down_peak', 'extra_down_peak' => 'base_down_peak', ]; /* INTERFACES */ public function getBillingIntervalAttribute(): int { return 1; // Monthly } public function products() { return $this->hasMany(ProductBroadband::class,'supplier_item_id','id'); } /* METHODS */ /** * Determine how traffic is counted for Broadband links. * * Configuration allows for traffic to fit into the following categories: * + down_peak, when not NULL, traffic is included to value of this metric, extra traffic is charged per extra_peak * + down_offpeak, when not NULL, traffic is included to the value of metric, extra traffic is charged per extra_offpeak * * If: * + UPLOADS are charged and there are no PEAK/OFFPEAK periods (therefore all * traffic is charged), the allowance will be shown as 1 metric - TRAFFIC. * + UPLOADS are charged and there are PEAK/OFFPEAK periods the allowance * will be shown as 2 metrics - PEAK/OFFPEAK. * + UPLOADS are NOT charged and there are no PEAK/OFFPEAK periods the allowance * will be shown as 1 metrics - TRAFFIC. * + UPLOADS are NOT charged and there are PEAK/OFFPEAK periods the allowance * will be shown as 2 metrics - PEAK/OFFPEAK. * * Thus: * (x = up/down, Y=peak/offpeak) * * + If base_x_Y is NULL, all Y traffic is FREE (ignore respective extra_x_Y setting). * + If base_x_Y is a number, all Y traffic is FREE up to the number (evaluate extra_x_Y setting). * + If extra_x_Y is a number, charge this amount for traffic over base_x_Y. * * + If extra_down_peak is NULL this is invalid, treat base_down_peak as NULL * + If extra_down_offpeak is NULL add traffic_down_offpeak to traffic_down_peak * + If extra_up_peak is NULL add traffic_up_peak to traffic_down_peak * + If extra_up_offpeak is NULL add traffic_up_offpeak to traffic_down_offpeak * * @param Collection|null $config The configuration of the link, if NULL assume the supplieres configuration * @param array $data The traffic used on this link, determine whats left or over * @param bool $ceil Round the numbers to integers * @return array|string */ public function allowance(Collection $config=NULL,array $data=[],bool $ceil=TRUE) { $map = collect(self::traffic_map); $merge = collect(self::traffic_merge); if (is_null($config)) $config = collect($config); // If config is null, use the configuration from this Model if (! $config->count()) { // Base Config foreach ($map->keys() as $k) $config->put($k,$this->{$k}); // Excess Config foreach ($map->values() as $k) $config->put($k,$this->{$k}); // Shaped or Charge $config->put('shaped',$this->extra_shaped); $config->put('charged',$this->extra_charged); // Metric - used to round down data in $data. $config->put('metric',$this->metric); } $result = collect(); // If data is empty, we'll report on allowance, otherwise we'll report on consumption $report = ! $data; // Work out if we charge each period foreach ($map as $k => $v) { // Anything NULL is not counted if (is_null($config->get($k))) continue; $x = $report ? $config->get($k) : ($config->get($k)-Arr::get($data,$k,0)); if ($ceil) $x = (int)ceil($x); // Non-NULL entries are counted as is if (! is_null($config->get($v))) { // Existing value for this item to be added $value = $result->has($k) ? $result->get($k) : 0; $result->put($k,$value+$x); // NULL entries are merged into another key } else { // New Key for this item $key = $merge->get($v); // Existing value for this item to be added $value = $result->has($key) ? $result->get($key) : 0; // Any value in the existing key, add it too. if ($k !== $key AND $result->has($k)) { $value += $result->get($k); $result->forget($k); } $result->put($key,$value+$x); } } if ($config->has('metric') AND $config->get('metric')) $result->transform(function($item) use ($config,$ceil) { return $ceil ? (int)ceil($item/$config->get('metric')) : $item/$config->get('metric'); }); return $result; } }