diff --git a/db/secondbase/migrate/20180911180345_fix_price_rounding.rb b/db/secondbase/migrate/20180911180345_fix_price_rounding.rb new file mode 100644 index 000000000..c71c15e82 --- /dev/null +++ b/db/secondbase/migrate/20180911180345_fix_price_rounding.rb @@ -0,0 +1,99 @@ +class FixPriceRounding < ActiveRecord::Migration[5.1] + def up + execute %q{ + CREATE or replace FUNCTION switch.vendor_price_round(i_config sys.config, i_amount numeric) RETURNS numeric + LANGUAGE plpgsql COST 10 + AS $$ + DECLARE + + BEGIN + + case i_config.vendor_amount_round_mode_id + when 1 then -- disable rounding + return i_amount; + when 2 then --always up + return trunc(i_amount, i_config.vendor_amount_round_precision) + + (mod(i_amount::numeric, power(10,-i_config.vendor_amount_round_precision)::numeric)>0)::int*power(10,-i_config.vendor_amount_round_precision); + when 3 then --always down + return trunc(i_amount, i_config.vendor_amount_round_precision); + when 4 then -- math + return round(i_amount, i_config.vendor_amount_round_precision); + else -- fallback to math rules + return round(i_amount, i_config.vendor_amount_round_precision); + end case; + END; + $$; + + + CREATE or replace FUNCTION switch.customer_price_round(i_config sys.config, i_amount numeric) RETURNS numeric + LANGUAGE plpgsql COST 10 + AS $$ + DECLARE + BEGIN + + case i_config.customer_amount_round_mode_id + when 1 then -- disable rounding + return i_amount; + when 2 then --always up + return trunc(i_amount, i_config.customer_amount_round_precision) + + (mod(i_amount::numeric, power(10,-i_config.customer_amount_round_precision)::numeric)>0)::int*power(10,-i_config.customer_amount_round_precision); + when 3 then --always down + return trunc(i_amount, i_config.customer_amount_round_precision); + when 4 then -- math + return round(i_amount, i_config.customer_amount_round_precision); + else -- fallback to math rules + return round(i_amount, i_config.customer_amount_round_precision); + end case; + END; + $$; +} + end + + def down +execute %q{ + CREATE or replace FUNCTION switch.vendor_price_round(i_config sys.config, i_amount numeric) RETURNS numeric + LANGUAGE plpgsql COST 10 + AS $$ + DECLARE + + BEGIN + + case i_config.vendor_amount_round_mode_id + when 1 then -- disable rounding + return i_amount; + when 2 then --always up + return trunc(i_amount, i_config.vendor_amount_round_precision) + power(10 , - i_config.vendor_amount_round_precision); + when 3 then --always down + return trunc(i_amount, i_config.vendor_amount_round_precision); + when 4 then -- math + return round(i_amount, i_config.vendor_amount_round_precision); + else -- fallback to math rules + return round(i_amount, i_config.vendor_amount_round_precision); + end case; + END; + $$; + + + CREATE or replace FUNCTION switch.customer_price_round(i_config sys.config, i_amount numeric) RETURNS numeric + LANGUAGE plpgsql COST 10 + AS $$ + DECLARE + BEGIN + + case i_config.customer_amount_round_mode_id + when 1 then -- disable rounding + return i_amount; + when 2 then --always up + return trunc(i_amount, i_config.customer_amount_round_precision) + power(10 , - i_config.customer_amount_round_precision); + when 3 then --always down + return trunc(i_amount, i_config.customer_amount_round_precision); + when 4 then -- math + return round(i_amount, i_config.customer_amount_round_precision); + else -- fallback to math rules + return round(i_amount, i_config.customer_amount_round_precision); + end case; + END; + $$; +} + end +end diff --git a/db/secondbase/structure.sql b/db/secondbase/structure.sql index 69ee2984f..7cd26f1ad 100644 --- a/db/secondbase/structure.sql +++ b/db/secondbase/structure.sql @@ -972,23 +972,24 @@ CREATE TABLE sys.config ( CREATE FUNCTION switch.customer_price_round(i_config sys.config, i_amount numeric) RETURNS numeric LANGUAGE plpgsql COST 10 AS $$ - DECLARE - BEGIN + DECLARE + BEGIN - case i_config.customer_amount_round_mode_id + case i_config.customer_amount_round_mode_id when 1 then -- disable rounding - return i_amount; + return i_amount; when 2 then --always up - return trunc(i_amount, i_config.customer_amount_round_precision) + power(10 , - i_config.customer_amount_round_precision); + return trunc(i_amount, i_config.customer_amount_round_precision) + + (mod(i_amount::numeric, power(10,-i_config.customer_amount_round_precision)::numeric)>0)::int*power(10,-i_config.customer_amount_round_precision); when 3 then --always down - return trunc(i_amount, i_config.customer_amount_round_precision); + return trunc(i_amount, i_config.customer_amount_round_precision); when 4 then -- math - return round(i_amount, i_config.customer_amount_round_precision); + return round(i_amount, i_config.customer_amount_round_precision); else -- fallback to math rules - return round(i_amount, i_config.customer_amount_round_precision); - end case; - END; - $$; + return round(i_amount, i_config.customer_amount_round_precision); + end case; + END; + $$; -- @@ -1024,24 +1025,25 @@ CREATE FUNCTION switch.duration_round(i_config sys.config, i_duration double pre CREATE FUNCTION switch.vendor_price_round(i_config sys.config, i_amount numeric) RETURNS numeric LANGUAGE plpgsql COST 10 AS $$ - DECLARE + DECLARE - BEGIN + BEGIN - case i_config.vendor_amount_round_mode_id - when 1 then -- disable rounding - return i_amount; - when 2 then --always up - return trunc(i_amount, i_config.vendor_amount_round_precision) + power(10 , - i_config.vendor_amount_round_precision); - when 3 then --always down - return trunc(i_amount, i_config.vendor_amount_round_precision); - when 4 then -- math - return round(i_amount, i_config.vendor_amount_round_precision); - else -- fallback to math rules - return round(i_amount, i_config.vendor_amount_round_precision); - end case; - END; - $$; + case i_config.vendor_amount_round_mode_id + when 1 then -- disable rounding + return i_amount; + when 2 then --always up + return trunc(i_amount, i_config.vendor_amount_round_precision) + + (mod(i_amount::numeric, power(10,-i_config.vendor_amount_round_precision)::numeric)>0)::int*power(10,-i_config.vendor_amount_round_precision); + when 3 then --always down + return trunc(i_amount, i_config.vendor_amount_round_precision); + when 4 then -- math + return round(i_amount, i_config.vendor_amount_round_precision); + else -- fallback to math rules + return round(i_amount, i_config.vendor_amount_round_precision); + end case; + END; + $$; -- @@ -6177,7 +6179,7 @@ ALTER TABLE ONLY sys.config -- PostgreSQL database dump complete -- -SET search_path TO cdr, reports, billing; +SET search_path TO cdr, reports, billing, public; INSERT INTO "public"."schema_migrations" (version) VALUES ('20170907204350'), @@ -6194,6 +6196,7 @@ INSERT INTO "public"."schema_migrations" (version) VALUES ('20180607135226'), ('20180611140540'), ('20180619091111'), -('20180621130107'); +('20180621130107'), +('20180911180345'); diff --git a/spec/models/cdr/cdr_spec.rb b/spec/models/cdr/cdr_spec.rb index 3d9abf94f..14e03add1 100644 --- a/spec/models/cdr/cdr_spec.rb +++ b/spec/models/cdr/cdr_spec.rb @@ -382,6 +382,82 @@ ) end + + context "When call duration =0 and price already rounded" do + before do + #always UP, precision 4 + System::CdrConfig.take!.update!( + customer_amount_round_mode_id: 2, + customer_amount_round_precision: 4, + vendor_amount_round_mode_id: 2, + vendor_amount_round_precision: 4 + ) + end + + let(:i_time_data) do + { + "time_start": time_start.to_f, + "leg_b_time": leg_b_time.to_f, + "time_connect": nil, + "time_end": time_end.to_f, + "time_1xx": time_1xx.to_f, + "time_18x": time_18x.to_f, + "time_limit": 7200, + "isup_propagation_delay": 0 + }.to_json + end + + let(:writecdr_parameters) do + %Q{ + 't', + '10', + '3', + '4', + 't', + '1', + '127.0.0.3', + '1015', + '127.0.0.2', + '1926', + '1', + '127.0.0.5', + '1036', + '127.0.0.4', + '5065', + '#{i_time_data}', + 'f', + '200', + 'Bye', + '3', + '200', + 'Bye', + '200', + 'Bye', + 'dhgxlgaifhhmovy@elo', + '08889A81-5ABE27EE000480C0-EE666700', + '73F4856A-5ABE27EE00047ECE-CD83B700', + '/var/spool/sems/dump/73F4856A-5ABE27EE00047ECE-CD83B700_10.pcap', + '0', + 'f', + '{"lega_rx_payloads":"/pcmu","lega_tx_payloads":"/pcmu","legb_rx_payloads":"/pcmu","legb_tx_payloads":"/pcmu","lega_rx_bytes":153596,"lega_tx_bytes":152736,"legb_rx_bytes":152736,"legb_tx_bytes":153596,"lega_rx_decode_errs":1763,"lega_rx_no_buf_errs":1025,"lega_rx_parse_errs":1710,"legb_rx_decode_errs":1777,"legb_rx_no_buf_errs":1000,"legb_rx_parse_errs":1482}', + '', + '', + '[]', + 3::smallint, + 1551231112::bigint, + NULL, + '{"core":"1.7.60-4","yeti":"1.7.30-1","aleg":"Twinkle/1.10.1","bleg":"Localhost Media Gateway"}', + 'f', + '{"customer_auth_name":"Customer Auth for trunk 1","customer_id":1105,"vendor_id":1755,"customer_acc_id":1886,"vendor_acc_id":32,"customer_auth_id":20084,"destination_id":4201534,"destination_prefix":"","dialpeer_id":1376789,"dialpeer_prefix":"","orig_gw_id":17,"term_gw_id":39,"routing_group_id":22,"rateplan_id":14,"destination_initial_rate":"0.0001","destination_next_rate":"0.0001","destination_initial_interval":60,"destination_next_interval":11,"destination_rate_policy_id":1442,"dialpeer_initial_interval":12,"dialpeer_next_interval":13,"dialpeer_next_rate":"1.0","destination_fee":"0.0","dialpeer_initial_rate":"1.0","dialpeer_fee":"0.0","dst_prefix_in":"380947100008","dst_prefix_out":"echotest","src_prefix_in":"h","src_prefix_out":"380947111223","src_name_in":"","src_name_out":"","diversion_in":"rspec-diversion-in","diversion_out":"rspec-diversion-out","auth_orig_protocol_id":1567,"auth_orig_ip":"127.0.0.1","auth_orig_port":1947,"dst_country_id":222,"dst_network_id":1533,"dst_prefix_routing":"380947100008","src_prefix_routing":"380947111223","routing_plan_id":1,"lrn":"rspec-lrn","lnp_database_id":111,"from_domain":"node-10.yeti-sandbox.localhost","to_domain":"node-10.yeti-sandbox.localhost","ruri_domain":"node-10.yeti-sandbox.localhost","src_area_id":222,"dst_area_id":333,"routing_tag_ids":"{9}","pai_in":"rspec-pai-in","ppi_in":"rspec-ppi-in","privacy_in":"rspec-privacy-in","rpid_in":"rspec-rpid-in","rpid_privacy_in":"rspec-rpid-privacy-in","pai_out":"rspec-pai-out","ppi_out":"rspec-ppi-out","privacy_out":"rspec-privacy-out","rpid_out":"rspec-rpid-out","rpid_privacy_out":"rspec-rpid-privacy-out","customer_acc_check_balance":true,"destination_reverse_billing":false,"dialpeer_reverse_billing":false,"customer_auth_external_id":1504,"customer_external_id":156998,"vendor_external_id":1111,"customer_acc_external_id":156998,"vendor_acc_external_id":2222,"orig_gw_external_id":1,"term_gw_external_id":4444,"customer_acc_vat":"0.0"}' + } + end + it "customer amount" do + expect { subject }.to change {described_class.count}.by(1) + expect(described_class.last.customer_price).to eq(0) + expect(described_class.last.vendor_price).to eq(0) + end + end + context "When customer round mode=2" do before do #always UP, precision 4