diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index 7815b08de..429a5430d 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -288,6 +288,7 @@ CREATE TABLE tp_derived_chargers ( `setup_time_field` varchar(24) NOT NULL, `answer_time_field` varchar(24) NOT NULL, `usage_field` varchar(24) NOT NULL, + `supplier_field` varchar(24) NOT NULL, `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`) diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 6cfdd7b09..7b3e8c336 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -272,6 +272,7 @@ CREATE TABLE tp_derived_chargers ( setup_time_field VARCHAR(24) NOT NULL, answer_time_field VARCHAR(24) NOT NULL, usage_field VARCHAR(24) NOT NULL, + supplier_field VARCHAR(24) NOT NULL, created_at TIMESTAMP ); CREATE INDEX tpderivedchargers_idx ON tp_derived_chargers (tpid,loadid,direction,tenant,category,account,subject); diff --git a/data/tariffplans/prepaid1centpsec/DerivedChargers.csv b/data/tariffplans/prepaid1centpsec/DerivedChargers.csv index 7246f65fe..780806a40 100644 --- a/data/tariffplans/prepaid1centpsec/DerivedChargers.csv +++ b/data/tariffplans/prepaid1centpsec/DerivedChargers.csv @@ -1,5 +1,5 @@ -#Direction,Tenant,Tor,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,DurationField -*out,cgrates.org,call,dan,dan,extra1,,^prepaid,,,,^rif,^rif,,,,^1s -*out,cgrates.org,call,dan,dan,extra2,,,,,,^ivo,^ivo,,,, -*out,cgrates.org,call,dan,dan,extra3,~filterhdr1:s/(.+)/special_run3/,,,,,^runusr3,^runusr3,,,, -*out,cgrates.org,call,dan,*any,extra1,,,,,,^rif2,^rif2,,,, +#Direction,Tenant,Tor,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField,SupplierField +*out,cgrates.org,call,dan,dan,extra1,,^prepaid,,,,^rif,^rif,,,,^1s,*default +*out,cgrates.org,call,dan,dan,extra2,,,,,,^ivo,^ivo,,,,,*default +*out,cgrates.org,call,dan,dan,extra3,~filterhdr1:s/(.+)/special_run3/,,,,,^runusr3,^runusr3,,,,,*default +*out,cgrates.org,call,dan,*any,extra1,,,,,,^rif2,^rif2,,,,,*default diff --git a/data/tariffplans/tutorial/DerivedChargers.csv b/data/tariffplans/tutorial/DerivedChargers.csv index ddda092f7..631600938 100644 --- a/data/tariffplans/tutorial/DerivedChargers.csv +++ b/data/tariffplans/tutorial/DerivedChargers.csv @@ -1,2 +1,2 @@ -#Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,CategoryField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField -*out,cgrates.org,call,1001,1001,derived_run1,,^*rated,*default,*default,*default,*default,^1002,*default,*default,*default,*default +#Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,CategoryField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField,SupplierField +*out,cgrates.org,call,1001,1001,derived_run1,,^*rated,*default,*default,*default,*default,^1002,*default,*default,*default,*default,*default diff --git a/engine/loader_csv.go b/engine/loader_csv.go index aa52096ec..a5a5aa376 100644 --- a/engine/loader_csv.go +++ b/engine/loader_csv.go @@ -934,6 +934,7 @@ func (csvr *CSVReader) LoadDerivedChargers() (err error) { SetupTimeField: ValueOrDefault(record[14], "*default"), AnswerTimeField: ValueOrDefault(record[15], "*default"), UsageField: ValueOrDefault(record[16], "*default"), + SupplierField: ValueOrDefault(record[17], "*default"), }); err != nil { return err } @@ -954,6 +955,7 @@ func (csvr *CSVReader) LoadDerivedChargers() (err error) { SetupTimeField: ValueOrDefault(record[14], "*default"), AnswerTimeField: ValueOrDefault(record[15], "*default"), UsageField: ValueOrDefault(record[16], "*default"), + SupplierField: ValueOrDefault(record[17], "*default"), }} } } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 6d7e5d584..c4de6a124 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -189,9 +189,9 @@ vdf,emptyY,*out,TOPUP_EMPTY_AT, derivedCharges = ` #Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField -*out,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1/,^prepaid,,,,rif,rif,,,, -*out,cgrates.org,call,dan,dan,extra2,,,,,,ivo,ivo,,,, -*out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,, +*out,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1/,^prepaid,,,,rif,rif,,,,, +*out,cgrates.org,call,dan,dan,extra2,,,,,,ivo,ivo,,,,, +*out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,,, ` cdrStats = ` #Id,QueueLength,TimeWindow,Metrics,SetupInterval,TOR,CdrHost,CdrSource,ReqType,Direction,Tenant,Category,Account,Subject,DestinationPrefix,UsageInterval,MediationRunIds,RatedAccount,RatedSubject,CostInterval,Triggers @@ -955,11 +955,12 @@ func TestLoadDerivedChargers(t *testing.T) { t.Error("Failed to load derivedChargers: ", csvr.derivedChargers) } expCharger1 := utils.DerivedChargers{ - &utils.DerivedCharger{RunId: "extra1", RunFilters: "^filteredHeader1/filterValue1/", ReqTypeField: "^prepaid", DirectionField: "*default", - TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", - SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", - AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, + &utils.DerivedCharger{RunId: "extra1", RunFilters: "^filteredHeader1/filterValue1/", ReqTypeField: "^prepaid", DirectionField: utils.META_DEFAULT, + TenantField: utils.META_DEFAULT, CategoryField: utils.META_DEFAULT, AccountField: "rif", SubjectField: "rif", DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT}, + &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: utils.META_DEFAULT, AccountField: "ivo", SubjectField: "ivo", DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT}, } keyCharger1 := utils.DerivedChargersKey("*out", "cgrates.org", "call", "dan", "dan") if !reflect.DeepEqual(csvr.derivedChargers[keyCharger1], expCharger1) { diff --git a/engine/loader_db.go b/engine/loader_db.go index b7dd87e24..5f0832b36 100644 --- a/engine/loader_db.go +++ b/engine/loader_db.go @@ -916,7 +916,7 @@ func (dbr *DbReader) LoadDerivedChargersFiltered(filter *utils.TPDerivedChargers } for _, tpDc := range tpDcs.DerivedChargers { if dc, err := utils.NewDerivedCharger(tpDc.RunId, tpDc.RunFilters, tpDc.ReqTypeField, tpDc.DirectionField, tpDc.TenantField, tpDc.CategoryField, - tpDc.AccountField, tpDc.SubjectField, tpDc.DestinationField, tpDc.SetupTimeField, tpDc.AnswerTimeField, tpDc.UsageField); err != nil { + tpDc.AccountField, tpDc.SubjectField, tpDc.DestinationField, tpDc.SetupTimeField, tpDc.AnswerTimeField, tpDc.UsageField, tpDc.SupplierField); err != nil { return err } else { allDcs[tag] = append(allDcs[tag], dc) diff --git a/engine/loader_helpers.go b/engine/loader_helpers.go index f28f43f45..f4109959f 100644 --- a/engine/loader_helpers.go +++ b/engine/loader_helpers.go @@ -394,8 +394,8 @@ var FileValidators = map[string]*FileLineRegexValidator{ regexp.MustCompile(`(?:\w+\s*),(?:(\w+;?)+\s*),(?:\*out\s*),(?:\w+\s*),(?:\w+\s*)$`), "Tenant([0-9A-Za-z_]),Account([0-9A-Za-z_.]),Direction(*out),ActionTimingsTag([0-9A-Za-z_]),ActionTriggersTag([0-9A-Za-z_])"}, utils.DERIVED_CHARGERS_CSV: &FileLineRegexValidator{utils.DERIVED_CHARGERS_NRCOLS, - regexp.MustCompile(`^(?:\*out),(?:[0-9A-Za-z_\.]+\s*),(?:\w+\s*),(?:\w+\s*),(?:\*any\s*|\w+\s*),(?:\w+\s*),(?:[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?$`), - "Direction(*out),Tenant[0-9A-Za-z_],Category([0-9A-Za-z_]),Account[0-9A-Za-z_],Subject([0-9A-Za-z_]|*any),RunId([0-9A-Za-z_]),RunFilter([^~]*[0-9A-Za-z_/]),ReqTypeField([^~]*[0-9A-Za-z_/]|*default),DirectionField([^~]*[0-9A-Za-z_/]|*default),TenantField([^~]*[0-9A-Za-z_/]|*default),TorField([^~]*[0-9A-Za-z_/]|*default),AccountField([^~]*[0-9A-Za-z_/]|*default),SubjectField([^~]*[0-9A-Za-z_/]|*default),DestinationField([^~]*[0-9A-Za-z_/]|*default),SetupTimeField([^~]*[0-9A-Za-z_/]|*default),AnswerTimeField([^~]*[0-9A-Za-z_/]|*default),DurationField([^~]*[0-9A-Za-z_/]|*default)"}, + regexp.MustCompile(`^(?:\*out),(?:[0-9A-Za-z_\.]+\s*),(?:\w+\s*),(?:\w+\s*),(?:\*any\s*|\w+\s*),(?:\w+\s*),(?:[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?,(?:\*default\s*|[~^]*[0-9A-Za-z_/:().+]+\s*)?$`), + "Direction(*out),Tenant[0-9A-Za-z_],Category([0-9A-Za-z_]),Account[0-9A-Za-z_],Subject([0-9A-Za-z_]|*any),RunId([0-9A-Za-z_]),RunFilter([^~]*[0-9A-Za-z_/]),ReqTypeField([^~]*[0-9A-Za-z_/]|*default),DirectionField([^~]*[0-9A-Za-z_/]|*default),TenantField([^~]*[0-9A-Za-z_/]|*default),TorField([^~]*[0-9A-Za-z_/]|*default),AccountField([^~]*[0-9A-Za-z_/]|*default),SubjectField([^~]*[0-9A-Za-z_/]|*default),DestinationField([^~]*[0-9A-Za-z_/]|*default),SetupTimeField([^~]*[0-9A-Za-z_/]|*default),AnswerTimeField([^~]*[0-9A-Za-z_/]|*default),UsageField([^~]*[0-9A-Za-z_/]|*default),SupplierField([^~]*[0-9A-Za-z_/]|*default)"}, utils.CDR_STATS_CSV: &FileLineRegexValidator{utils.CDR_STATS_NRCOLS, regexp.MustCompile(`.+`), //ToDo: Fix me with proper rules "Id,QueueLength,TimeWindow,Metric,SetupInterval,TOR,CdrHost,CdrSource,ReqType,Direction,Tenant,Category,Account,Subject,DestinationPrefix,UsageInterval,MediationRunIds,RatedAccount,RatedSubject,CostInterval,Triggers(*?[0-9A-Za-z_]),Strategy(*[0-9A-Za-z_]),RatingSubject(*?[0-9A-Za-z_])"}, diff --git a/engine/loader_helpers_test.go b/engine/loader_helpers_test.go index e199d263a..55ea7409e 100644 --- a/engine/loader_helpers_test.go +++ b/engine/loader_helpers_test.go @@ -94,18 +94,18 @@ DUMMY,INVALID;DATA cgrates.org,1002;1006,*out,PACKAGE_10,STANDARD_TRIGGERS ` var derivedChargesSample = `#Direction,Tenant,Tor,Account,Subject,RunId,ReqTypeField,DirectionField,TenantField,TorField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,DurationField -*out,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1,^prepaid,,,,rif,rif,,,, +*out,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1,^prepaid,,,,rif,rif,,,,,*default *out,cgrates.org,,dan,dan,extra1,^filteredHeader1/filterValue1,^prepaid,,,,rif,rif,,,, *in,cgrates.org,call,dan,dan,extra1,^filteredHeader1/filterValue1,^prepaid,,,,rif,rif,,,, DUMMY_DATA -*out,cgrates.org,call,dan,dan,extra2,,,,,,ivo,ivo,,,, -*out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,, +*out,cgrates.org,call,dan,dan,extra2,,,,,,ivo,ivo,,,,, +*out,cgrates.org,call,dan,*any,extra1,,,,,,rif2,rif2,,,,, *out,cgrates.org,call,dan,*any,*any,,,,,,rif2,rif2,,,, *out,cgrates.org,call,dan,*any,*default,,*default,*default,*default,*default,rif2,rif2,*default,*default,*default,*default -*out,cgrates.org,call,dan,*any,test,^test,^test,^test,^test,^test,^test,^test,^test,^test,^test,^test -*out,cgrates.org,call,dan,*any,run1,,,,,,,,,,, +*out,cgrates.org,call,dan,*any,test,^test,^test,^test,^test,^test,^test,^test,^test,^test,^test,^test,^test +*out,cgrates.org,call,dan,*any,run1,,,,,,,,,,,, *out,cgrates.org,call,dan,*default,,,,,,,,,,,, -*out,cgrates.org,call,dan,dan,extra3,~filterhdr1:s/(.+)/special_run3/,,,,,^runusr3,^runusr3,,,, +*out,cgrates.org,call,dan,dan,extra3,~filterhdr1:s/(.+)/special_run3/,,,,,^runusr3,^runusr3,,,,, ` func TestTimingsValidator(t *testing.T) { diff --git a/engine/models.go b/engine/models.go index b29d8234d..0e3d2a7fb 100644 --- a/engine/models.go +++ b/engine/models.go @@ -238,6 +238,7 @@ type TpDerivedCharger struct { SetupTimeField string AnswerTimeField string UsageField string + SupplierField string CreatedAt time.Time } diff --git a/engine/responder_test.go b/engine/responder_test.go index 66397961b..f5f5ee34c 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -125,18 +125,22 @@ func TestGetSessionRuns(t *testing.T) { testTenant := "vdf" cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2", - Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), + Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Supplier: "suppl1", MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"} keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan2", "dan2") - dfDC := &utils.DerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", - AccountField: "*default", SubjectField: "*default", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"} - extra1DC := &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^" + utils.META_PREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "^0", - AccountField: "^minitsboy", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"} - extra2DC := &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", - AccountField: "^ivo", SubjectField: "^ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"} - extra3DC := &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: "*default", TenantField: "*default", CategoryField: "^0", - AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"} + dfDC := &utils.DerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: utils.META_DEFAULT, AccountField: utils.META_DEFAULT, SubjectField: utils.META_DEFAULT, DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} + extra1DC := &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^" + utils.META_PREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: "^0", AccountField: "^minitsboy", SubjectField: "^rif", DestinationField: "^0256", + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} + extra2DC := &utils.DerivedCharger{RunId: "extra2", ReqTypeField: utils.META_DEFAULT, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: utils.META_DEFAULT, AccountField: "^ivo", SubjectField: "^ivo", DestinationField: utils.META_DEFAULT, + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} + extra3DC := &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^" + utils.META_PSEUDOPREPAID, DirectionField: utils.META_DEFAULT, TenantField: utils.META_DEFAULT, + CategoryField: "^0", AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", + SetupTimeField: utils.META_DEFAULT, AnswerTimeField: utils.META_DEFAULT, UsageField: utils.META_DEFAULT, SupplierField: utils.META_DEFAULT} charger1 := utils.DerivedChargers{extra1DC, extra2DC, extra3DC} if err := accountingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { t.Error("Error on setting DerivedChargers", err.Error()) diff --git a/engine/storage_mysql_local_test.go b/engine/storage_mysql_local_test.go index 751a74722..39c8eeafe 100644 --- a/engine/storage_mysql_local_test.go +++ b/engine/storage_mysql_local_test.go @@ -212,7 +212,8 @@ func TestMySQLSetGetTPDerivedChargers(t *testing.T) { if !*testLocal { return } - dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", UsageField: "cgr_duration"} + dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", + UsageField: "cgr_duration", SupplierField: "^supplier1"} dcs := &utils.TPDerivedChargers{TPid: TEST_SQL, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: []*utils.TPDerivedCharger{dc}} DCS_ID := dcs.GetDerivedChargesId() setDCs := map[string][]*utils.TPDerivedCharger{DCS_ID: []*utils.TPDerivedCharger{dc}} diff --git a/engine/storage_psql_local_test.go b/engine/storage_psql_local_test.go index 03be6a08f..eddfec222 100644 --- a/engine/storage_psql_local_test.go +++ b/engine/storage_psql_local_test.go @@ -214,7 +214,8 @@ func TestPSQLSetGetTPDerivedChargers(t *testing.T) { if !*testLocal { return } - dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", UsageField: "cgr_duration"} + dc := &utils.TPDerivedCharger{RunId: utils.DEFAULT_RUNID, ReqTypeField: "^" + utils.META_PREPAID, AccountField: "^rif", SubjectField: "^rif", + UsageField: "cgr_duration", SupplierField: "^supplier1"} dcs := &utils.TPDerivedChargers{TPid: TEST_SQL, Direction: utils.OUT, Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dan", DerivedChargers: []*utils.TPDerivedCharger{dc}} DCS_ID := dcs.GetDerivedChargesId() setDCs := map[string][]*utils.TPDerivedCharger{DCS_ID: []*utils.TPDerivedCharger{dc}} diff --git a/engine/storage_sql.go b/engine/storage_sql.go index f78759aca..cef3b4053 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -454,6 +454,7 @@ func (self *SQLStorage) SetTPDerivedChargers(tpid string, sgs map[string][]*util SetupTimeField: dc.SetupTimeField, AnswerTimeField: dc.AnswerTimeField, UsageField: dc.UsageField, + SupplierField: dc.SupplierField, CreatedAt: time.Now(), } if err := newDc.SetDerivedChargersId(dcId); err != nil { @@ -1480,6 +1481,7 @@ func (self *SQLStorage) GetTpDerivedChargers(dc *utils.TPDerivedChargers) (map[s SetupTimeField: tpDcMdl.SetupTimeField, AnswerTimeField: tpDcMdl.AnswerTimeField, UsageField: tpDcMdl.UsageField, + SupplierField: tpDcMdl.SupplierField, }) } return dcs, nil diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 4c45931c2..a9d92f69c 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -435,12 +435,13 @@ type TPDerivedChargers struct { DerivedChargers []*TPDerivedCharger } -//#Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,CategoryField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField +//#Direction,Tenant,Category,Account,Subject,RunId,RunFilter,ReqTypeField,DirectionField,TenantField,CategoryField,AccountField,SubjectField,DestinationField,SetupTimeField,AnswerTimeField,UsageField,SupplierField func (self *TPDerivedChargers) AsExportSlice() [][]string { retSlice := make([][]string, len(self.DerivedChargers)) for idx, dc := range self.DerivedChargers { retSlice[idx] = []string{self.Direction, self.Tenant, self.Category, self.Account, self.Subject, dc.RunId, dc.RunFilters, dc.ReqTypeField, - dc.DirectionField, dc.TenantField, dc.CategoryField, dc.AccountField, dc.SubjectField, dc.DestinationField, dc.SetupTimeField, dc.AnswerTimeField, dc.UsageField} + dc.DirectionField, dc.TenantField, dc.CategoryField, dc.AccountField, dc.SubjectField, dc.DestinationField, dc.SetupTimeField, dc.AnswerTimeField, + dc.UsageField, dc.SupplierField} } return retSlice } @@ -492,6 +493,7 @@ type TPDerivedCharger struct { SetupTimeField string AnswerTimeField string UsageField string + SupplierField string } type TPActionPlan struct { diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go index d269d9b99..ffa5f1993 100644 --- a/utils/apitpdata_test.go +++ b/utils/apitpdata_test.go @@ -344,37 +344,39 @@ func TestTPDerivedChargersAsExportSlice(t *testing.T) { RunId: "derived_run1", RunFilters: "", ReqTypeField: "^rated", - DirectionField: "*default", - TenantField: "*default", - CategoryField: "*default", - AccountField: "*default", + DirectionField: META_DEFAULT, + TenantField: META_DEFAULT, + CategoryField: META_DEFAULT, + AccountField: META_DEFAULT, SubjectField: "^1002", - DestinationField: "*default", - SetupTimeField: "*default", - AnswerTimeField: "*default", - UsageField: "*default", + DestinationField: META_DEFAULT, + SetupTimeField: META_DEFAULT, + AnswerTimeField: META_DEFAULT, + UsageField: META_DEFAULT, + SupplierField: META_DEFAULT, }, &TPDerivedCharger{ RunId: "derived_run2", RunFilters: "", ReqTypeField: "^rated", - DirectionField: "*default", - TenantField: "*default", - CategoryField: "*default", + DirectionField: META_DEFAULT, + TenantField: META_DEFAULT, + CategoryField: META_DEFAULT, AccountField: "^1002", - SubjectField: "*default", - DestinationField: "*default", - SetupTimeField: "*default", - AnswerTimeField: "*default", - UsageField: "*default", + SubjectField: META_DEFAULT, + DestinationField: META_DEFAULT, + SetupTimeField: META_DEFAULT, + AnswerTimeField: META_DEFAULT, + UsageField: META_DEFAULT, + SupplierField: META_DEFAULT, }, }, } expectedSlc := [][]string{ []string{"*out", "cgrates.org", "call", "1001", "1001", - "derived_run1", "", "^rated", "*default", "*default", "*default", "*default", "^1002", "*default", "*default", "*default", "*default"}, + "derived_run1", "", "^rated", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, "^1002", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT}, []string{"*out", "cgrates.org", "call", "1001", "1001", - "derived_run2", "", "^rated", "*default", "*default", "*default", "^1002", "*default", "*default", "*default", "*default", "*default"}, + "derived_run2", "", "^rated", META_DEFAULT, META_DEFAULT, META_DEFAULT, "^1002", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT}, } if slc := dcs.AsExportSlice(); !reflect.DeepEqual(expectedSlc, slc) { t.Errorf("Expecting: %+v, received: %+v", expectedSlc, slc) diff --git a/utils/consts.go b/utils/consts.go index 37a5c9014..71d839427 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -70,7 +70,7 @@ const ( ACTION_PLANS_NRCOLS = 4 ACTION_TRIGGERS_NRCOLS = 19 ACCOUNT_ACTIONS_NRCOLS = 5 - DERIVED_CHARGERS_NRCOLS = 17 + DERIVED_CHARGERS_NRCOLS = 18 CDR_STATS_NRCOLS = 21 ROUNDING_UP = "*up" ROUNDING_MIDDLE = "*middle" diff --git a/utils/derivedchargers.go b/utils/derivedchargers.go index 1be1ea9b6..dbcfad7d7 100644 --- a/utils/derivedchargers.go +++ b/utils/derivedchargers.go @@ -24,7 +24,7 @@ import ( ) // Wraps regexp compiling in case of rsr fields -func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld string) (dc *DerivedCharger, err error) { +func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld, supplFld string) (dc *DerivedCharger, err error) { if len(runId) == 0 { return nil, errors.New("Empty run id field") } @@ -95,6 +95,12 @@ func NewDerivedCharger(runId, runFilters, reqTypeFld, dirFld, tenantFld, catFld, return nil, err } } + dc.SupplierField = supplFld + if strings.HasPrefix(dc.SupplierField, REGEXP_PREFIX) || strings.HasPrefix(dc.SupplierField, STATIC_VALUE_PREFIX) { + if dc.rsrSupplierField, err = NewRSRField(dc.SupplierField); err != nil { + return nil, err + } + } return dc, nil } @@ -111,6 +117,7 @@ type DerivedCharger struct { SetupTimeField string // Field containing setup time information AnswerTimeField string // Field containing answer time information UsageField string // Field containing usage information + SupplierField string // Field containing supplier information rsrRunFilters []*RSRField // Storage for compiled Regexp in case of RSRFields rsrReqTypeField *RSRField rsrDirectionField *RSRField @@ -122,6 +129,7 @@ type DerivedCharger struct { rsrSetupTimeField *RSRField rsrAnswerTimeField *RSRField rsrUsageField *RSRField + rsrSupplierField *RSRField } func DerivedChargersKey(direction, tenant, category, account, subject string) string { @@ -145,6 +153,6 @@ func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) { func (dcs DerivedChargers) AppendDefaultRun() (DerivedChargers, error) { dcDf, _ := NewDerivedCharger(DEFAULT_RUNID, "", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, - META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT) + META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT) return append(dcs, dcDf), nil } diff --git a/utils/derivedchargers_test.go b/utils/derivedchargers_test.go index 6ee573eae..b07299cc7 100644 --- a/utils/derivedchargers_test.go +++ b/utils/derivedchargers_test.go @@ -58,9 +58,10 @@ func TestNewDerivedCharger(t *testing.T) { SetupTimeField: "setuptime1", AnswerTimeField: "answertime1", UsageField: "duration1", + SupplierField: "supplier1", } if dc1, err := NewDerivedCharger("test1", "", "reqtype1", "direction1", "tenant1", "tor1", "account1", "subject1", "destination1", - "setuptime1", "answertime1", "duration1"); err != nil { + "setuptime1", "answertime1", "duration1", "supplier1"); err != nil { t.Error("Unexpected error", err.Error) } else if !reflect.DeepEqual(edc1, dc1) { t.Errorf("Expecting: %v, received: %v", edc1, dc1) @@ -78,6 +79,7 @@ func TestNewDerivedCharger(t *testing.T) { SetupTimeField: "~setuptime2:s/sip:(.+)/$1/", AnswerTimeField: "~answertime2:s/sip:(.+)/$1/", UsageField: "~duration2:s/sip:(.+)/$1/", + SupplierField: "~supplier2:s/(.+)/$1/", } edc2.rsrRunFilters, _ = ParseRSRFields("^cdr_source/tdm_cdrs/", INFIELD_SEP) edc2.rsrReqTypeField, _ = NewRSRField("~reqtype2:s/sip:(.+)/$1/") @@ -90,6 +92,7 @@ func TestNewDerivedCharger(t *testing.T) { edc2.rsrSetupTimeField, _ = NewRSRField("~setuptime2:s/sip:(.+)/$1/") edc2.rsrAnswerTimeField, _ = NewRSRField("~answertime2:s/sip:(.+)/$1/") edc2.rsrUsageField, _ = NewRSRField("~duration2:s/sip:(.+)/$1/") + edc2.rsrSupplierField, _ = NewRSRField("~supplier2:s/(.+)/$1/") if dc2, err := NewDerivedCharger("test2", "^cdr_source/tdm_cdrs/", "~reqtype2:s/sip:(.+)/$1/", @@ -101,7 +104,8 @@ func TestNewDerivedCharger(t *testing.T) { "~destination2:s/sip:(.+)/$1/", "~setuptime2:s/sip:(.+)/$1/", "~answertime2:s/sip:(.+)/$1/", - "~duration2:s/sip:(.+)/$1/"); err != nil { + "~duration2:s/sip:(.+)/$1/", + "~supplier2:s/(.+)/$1/"); err != nil { t.Error("Unexpected error", err) } else if !reflect.DeepEqual(edc2, dc2) { t.Errorf("Expecting: %v, received: %v", edc2, dc2) @@ -118,16 +122,17 @@ func TestAppendDefaultRun(t *testing.T) { var dc1 DerivedChargers dcDf := &DerivedCharger{RunId: DEFAULT_RUNID, RunFilters: "", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: META_DEFAULT, SubjectField: META_DEFAULT, - DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT} + DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT, SupplierField: META_DEFAULT} eDc1 := DerivedChargers{dcDf} if dc1, _ = dc1.AppendDefaultRun(); !reflect.DeepEqual(dc1, eDc1) { t.Error("Unexpected result.") } dc2 := DerivedChargers{ - &DerivedCharger{RunId: "extra1", RunFilters: "", ReqTypeField: "reqtype2", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", - AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, - &DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", - AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, + &DerivedCharger{RunId: "extra1", RunFilters: "", ReqTypeField: "reqtype2", DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, + AccountField: "rif", SubjectField: "rif", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT}, + &DerivedCharger{RunId: "extra2", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT, TenantField: META_DEFAULT, CategoryField: META_DEFAULT, + AccountField: "ivo", SubjectField: "ivo", DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, AnswerTimeField: META_DEFAULT, + UsageField: META_DEFAULT, SupplierField: META_DEFAULT}, } eDc2 := append(dc2, dcDf) if dc2, _ = dc2.AppendDefaultRun(); !reflect.DeepEqual(dc2, eDc2) {