Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ jobs:
id: extract_tag

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Push to GHCR
uses: docker/build-push-action@v2
uses: docker/build-push-action@v6
with:
context: .
file: ci/trixie-package.Dockerfile
Expand Down
2 changes: 1 addition & 1 deletion app/admin/billing/currencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

decorate_with Billing::CurrencyDecorator

actions :index, :show, :edit, :update
actions :index, :show, :new, :create, :edit, :update

acts_as_audit
acts_as_safe_destroy
Expand Down
2 changes: 2 additions & 0 deletions app/admin/cdr/cdrs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,10 @@ def try_cdr_replica(&)
row :customer_price, &:decorated_customer_price
row :customer_price_no_vat
row :customer_duration, &:decorated_customer_duration
row :customer_currency_rate
row :vendor_price, &:decorated_vendor_price
row :vendor_duration, &:decorated_vendor_duration
row :vendor_currency_rate
row :profit, &:decorated_profit

row :rateplan
Expand Down
25 changes: 20 additions & 5 deletions app/assets/javascripts/cdr_stats.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$(document).ready(function () {
if ($('body').is('.index.cdrs')) {
$("#statistic_sidebar_section h3 span.sidebar_title").on('click', function (e) {
$("#statistic_sidebar_section .panel_contents").one('panel:opened', function () {
var div = $("#cdr_statistic");
if (div) {

Expand All @@ -16,10 +16,25 @@ $(document).ready(function () {

$("#cdr_stat_origination_asr").text(json.origination_asr);
$("#cdr_stat_termination_asr").text(json.termination_asr);
$("#cdr_stat_profit").text(json.profit);
$("#cdr_stat_origination_cost").text(json.origination_cost);
$("#cdr_stat_termination_cost").text(json.termination_cost);
$("#cdr_statistic_placeholder").show();
var currency = json.system_currency ? ' ' + json.system_currency : '';
$("#cdr_stat_profit").text(json.profit + currency);
$("#cdr_stat_origination_cost").text(json.origination_cost + currency);
var origByCurrency = $("#cdr_stat_origination_cost_by_currency").empty();
$.each(json.origination_cost_by_currency || [], function(_, e) {
origByCurrency.append($('<div class="cdr-stat-currency-row">').append(
$('<span class="cdr-stat-currency-label">').text(e.currency),
$('<span class="cdr-stat-currency-value">').text(e.amount)
));
});
$("#cdr_stat_termination_cost").text(json.termination_cost + currency);
var termByCurrency = $("#cdr_stat_termination_cost_by_currency").empty();
$.each(json.termination_cost_by_currency || [], function(_, e) {
termByCurrency.append($('<div class="cdr-stat-currency-row">').append(
$('<span class="cdr-stat-currency-label">').text(e.currency),
$('<span class="cdr-stat-currency-value">').text(e.amount)
));
});
$("#cdr_statistic_placeholder").css('display', 'grid');
});
}
});
Expand Down
9 changes: 7 additions & 2 deletions app/assets/javascripts/panel_toggle.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
$(document).ready(function() {
var title = $('.toggle.panel h3').wrapInner("<span class='sidebar_title'></span>");
title.find('span.sidebar_title').on('click', function (e) {
$(e.target).parent().next('.panel_contents').slideToggle("fast");
title.css('cursor', 'pointer').on('click', function (e) {
var panelContents = $(this).next('.panel_contents');
panelContents.slideToggle("fast", function() {
if ($(this).is(':visible')) {
$(this).trigger('panel:opened');
}
});
return false;
});
});
64 changes: 63 additions & 1 deletion app/assets/stylesheets/active_admin.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,69 @@ form.filter_form .filter_form_field.select_and_search input[type=text].search_fi

body.active_admin.index #active_admin_content {
.collapse_btn, .uncollapse_btn {
background-color: #3B76A4;
display: none;
}
}

.cdr-stat-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px 6px;
font-size: 1.05em;
padding: 2px 0;

.cdr-stat-cell {
display: flex;
flex-direction: column;

.cdr-stat-label {
color: #888;
font-size: 0.9em;
line-height: 1.2;
white-space: nowrap;
}

.cdr-stat-value {
font-weight: 600;
line-height: 1.3;
}
}

.cdr-stat-full {
grid-column: 1 / -1;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
gap: 8px;

.cdr-stat-value {
text-align: right;
white-space: nowrap;
}
}

.cdr-stat-separator {
grid-column: 1 / -1;
border-top: 1px solid #e8e8e8;
margin: 1px 0;
}

.cdr-stat-by-currency {
grid-column: 1 / -1;
padding: 0 0 1px 8px;

.cdr-stat-currency-row {
display: flex;
justify-content: space-between;
gap: 6px;
color: #666;
line-height: 1.4;
}

.cdr-stat-currency-value {
font-weight: 500;
white-space: nowrap;
}
}
}

Expand Down
16 changes: 15 additions & 1 deletion app/controllers/remote_stats_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ def cdrs_summary
acd: @data.decorated_acd,
origination_asr: @data.decorated_origination_asr,
termination_asr: @data.decorated_termination_asr,
system_currency: Billing::Currency.find_by(id: 0)&.name,
profit: @data.decorated_profit,
origination_cost: @data.decorated_customer_price,
termination_cost: @data.decorated_vendor_price
origination_cost_by_currency: cdr_cost_by_currency(@data.customer_price_by_currency),
termination_cost: @data.decorated_vendor_price,
termination_cost_by_currency: cdr_cost_by_currency(@data.vendor_price_by_currency)
)
end

Expand Down Expand Up @@ -132,4 +135,15 @@ def clean_search_params(params)
{}
end
end

def cdr_cost_by_currency(by_currency)
return [] if by_currency.blank?

currency_names = Billing::Currency.where(id: by_currency.keys.compact).pluck(:id, :name).to_h
by_currency.map do |currency_id, amount|
name = currency_id.nil? ? 'N/A' : (currency_names[currency_id] || currency_id.to_s)
formatted = ActionController::Base.helpers.number_to_currency(amount, delimiter: ' ', separator: '.', precision: 2, unit: '')
{ currency: name, amount: formatted }
end.sort_by { |e| e[:currency] }
end
end
50 changes: 38 additions & 12 deletions app/models/cdr/cdr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -418,18 +418,44 @@ def attempts
end

def self.scoped_stat
select("
count(nullif(is_last_cdr,false)) as originated_calls_count,
count(nullif(routing_attempt=2,false)) as rerouted_calls_count,
100*count(nullif(routing_attempt=2,false))::real/nullif(count(nullif(is_last_cdr,false)),0)::real as rerouted_calls_percent,
count(id) as termination_attempts_count,
coalesce(sum(duration),0) as calls_duration,
sum(duration)::float/nullif(count(nullif(success,false)),0)::float as ACD,
count(nullif(success,false))::float/nullif(count(nullif(is_last_cdr,false)),0)::float as origination_asr,
count(nullif(success,false))::float/nullif(count(id),0)::float as termination_asr,
sum(profit) as profit,
sum(customer_price) as customer_price,
sum(vendor_price) as vendor_price").to_a[0]
rows = select("
customer_currency_id,
vendor_currency_id,
count(nullif(is_last_cdr,false)) AS originated_calls_count,
count(nullif(routing_attempt=2,false)) AS rerouted_calls_count,
count(id) AS termination_attempts_count,
coalesce(sum(duration),0) AS calls_duration,
count(nullif(success,false)) AS success_count,
sum(profit) AS profit,
sum(customer_price) AS customer_price,
sum(customer_price * coalesce(customer_currency_rate,1)) AS customer_price_system,
sum(vendor_price) AS vendor_price,
sum(vendor_price * coalesce(vendor_currency_rate,1)) AS vendor_price_system
").group(:customer_currency_id, :vendor_currency_id).to_a

originated = rows.sum { |r| r.originated_calls_count.to_i }
rerouted = rows.sum { |r| r.rerouted_calls_count.to_i }
termination = rows.sum { |r| r.termination_attempts_count.to_i }
calls_duration = rows.sum { |r| r.calls_duration.to_i }
success_count = rows.sum { |r| r.success_count.to_i }

OpenStruct.new(
originated_calls_count: originated,
rerouted_calls_count: rerouted,
rerouted_calls_percent: originated > 0 ? 100.0 * rerouted / originated : 0,
termination_attempts_count: termination,
calls_duration: calls_duration,
acd: success_count > 0 ? calls_duration.to_f / success_count : nil,
origination_asr: originated > 0 ? success_count.to_f / originated : nil,
termination_asr: termination > 0 ? success_count.to_f / termination : nil,
profit: rows.sum { |r| r.profit.to_f },
customer_price: rows.sum { |r| r.customer_price_system.to_f },
customer_price_by_currency: rows.group_by(&:customer_currency_id)
.transform_values { |rs| rs.sum { |r| r.customer_price.to_f } },
vendor_price: rows.sum { |r| r.vendor_price_system.to_f },
vendor_price_by_currency: rows.group_by(&:vendor_currency_id)
.transform_values { |rs| rs.sum { |r| r.vendor_price.to_f } }
)
end

def self.provisioning_info
Expand Down
2 changes: 1 addition & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ en:
ui_type: "This field will be used in Service Resource of Customer API"
system_customer_portal_access_profile:
account: "Display Account default page"
currency:
billing_currency:
rate: "Exchange rate relative to the system currency. Set to how much 1 unit of this currency is worth in system currency. Example: if EURO is the system currency and 1 EURO = 5.05 UAH, then UAH rate = 1 / 5.05 ≈ 0.198."


Expand Down
87 changes: 45 additions & 42 deletions lib/resource_dsl/acts_as_cdr_stat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,51 @@ module ActsAsCdrStat
def acts_as_cdr_stat
section = ActiveAdmin::SidebarSection.new 'Statistic', class: 'toggle', only: :index do
div id: 'cdr_statistic', class: 'loader'
ul id: 'cdr_statistic_placeholder', style: 'display: none;' do
li do
span 'Originated calls:'
strong id: :cdr_stat_originated_calls_count
end
li do
span 'Rerouted calls:'
strong id: :cdr_stat_rerouted_calls_count
end
li do
span 'Termination attempts:'
strong id: :cdr_stat_termination_attempts_count
end

li do
span 'Total duration:'
strong id: :cdr_stat_calls_duration
end
li do
span 'ACD:'
strong id: :cdr_stat_acd
end
li do
span 'Origination ASR:'
strong id: :cdr_stat_origination_asr
end
li do
span 'Termination ASR:'
strong id: :cdr_stat_termination_asr
end
li do
span 'Profit:'
strong id: :cdr_stat_profit
end
li do
span 'Origination cost:'
strong id: :cdr_stat_origination_cost
end
li do
span 'Termination cost:'
strong id: :cdr_stat_termination_cost
end
div id: 'cdr_statistic_placeholder', class: 'cdr-stat-grid', style: 'display: none;' do
div class: 'cdr-stat-cell cdr-stat-full' do
span 'Originated calls', class: 'cdr-stat-label'
strong id: :cdr_stat_originated_calls_count, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell' do
span 'Terminated', class: 'cdr-stat-label'
strong id: :cdr_stat_termination_attempts_count, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell' do
span 'Rerouted', class: 'cdr-stat-label'
strong id: :cdr_stat_rerouted_calls_count, class: 'cdr-stat-value'
end
div class: 'cdr-stat-separator'
div class: 'cdr-stat-cell' do
span 'Duration', class: 'cdr-stat-label'
strong id: :cdr_stat_calls_duration, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell' do
span 'ACD', class: 'cdr-stat-label'
strong id: :cdr_stat_acd, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell' do
span 'Orig ASR', class: 'cdr-stat-label'
strong id: :cdr_stat_origination_asr, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell' do
span 'Term ASR', class: 'cdr-stat-label'
strong id: :cdr_stat_termination_asr, class: 'cdr-stat-value'
end
div class: 'cdr-stat-separator'
div class: 'cdr-stat-cell cdr-stat-full' do
span 'Profit', class: 'cdr-stat-label'
strong id: :cdr_stat_profit, class: 'cdr-stat-value'
end
div class: 'cdr-stat-cell cdr-stat-full' do
span 'Origination cost', class: 'cdr-stat-label'
strong id: :cdr_stat_origination_cost, class: 'cdr-stat-value'
end
div id: :cdr_stat_origination_cost_by_currency, class: 'cdr-stat-by-currency'
div class: 'cdr-stat-cell cdr-stat-full' do
span 'Termination cost', class: 'cdr-stat-label'
strong id: :cdr_stat_termination_cost, class: 'cdr-stat-value'
end
div id: :cdr_stat_termination_cost_by_currency, class: 'cdr-stat-by-currency'
end
end
config.sidebar_sections.unshift section
Expand Down
Loading