diff --git a/apier/v1/suppliers_it_test.go b/apier/v1/suppliers_it_test.go
index 5274c6573..af6493f01 100644
--- a/apier/v1/suppliers_it_test.go
+++ b/apier/v1/suppliers_it_test.go
@@ -58,6 +58,7 @@ var sTestsSupplierSV1 = []func(t *testing.T){
testV1SplSGetQOSSuppliers,
testV1SplSGetQOSSuppliers2,
testV1SplSGetQOSSuppliers3,
+ testV1SplSGetQOSSuppliersFiltred,
testV1SplSGetSupplierWithoutFilter,
testV1SplSSetSupplierProfiles,
testV1SplSUpdateSupplierProfiles,
@@ -673,6 +674,53 @@ func testV1SplSGetQOSSuppliers3(t *testing.T) {
}
}
+func testV1SplSGetQOSSuppliersFiltred(t *testing.T) {
+ ev := &engine.ArgsGetSuppliers{
+ CGREvent: utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "testV1SplSGetQOSSuppliers",
+ Event: map[string]interface{}{
+ "DistincMatch": "*qos_filtred",
+ },
+ },
+ }
+ eSpls := engine.SortedSuppliers{
+ ProfileID: "SPL_QOS_FILTRED",
+ Sorting: utils.MetaQOS,
+ SortedSuppliers: []*engine.SortedSupplier{
+ &engine.SortedSupplier{
+ SupplierID: "supplier1",
+ SortingData: map[string]interface{}{
+ "*acd:Stat_1": 11.0,
+ "*acd:Stat_1_1": 11.0,
+ "*asr:Stat_1": 100.0,
+ "*pdd:Stat_1_1": 12.0,
+ "*tcd:Stat_1": 22.0,
+ "*tcd:Stat_1_1": 11.0,
+ utils.Weight: 10.0,
+ },
+ },
+ &engine.SortedSupplier{
+ SupplierID: "supplier3",
+ SortingData: map[string]interface{}{
+ "*acd:Stat_3": 11.0,
+ "*asr:Stat_3": 100.0,
+ "*tcd:Stat_3": 11.0,
+ utils.Weight: 35.0,
+ },
+ },
+ },
+ }
+ var suplsReply engine.SortedSuppliers
+ if err := splSv1Rpc.Call(utils.SupplierSv1GetSuppliers,
+ ev, &suplsReply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(eSpls, suplsReply) {
+ t.Errorf("Expecting: %s, received: %s",
+ utils.ToJSON(eSpls), utils.ToJSON(suplsReply))
+ }
+}
+
func testV1SplSGetSupplierWithoutFilter(t *testing.T) {
ev := &engine.ArgsGetSuppliers{
CGREvent: utils.CGREvent{
diff --git a/data/tariffplans/testit/Filters.csv b/data/tariffplans/testit/Filters.csv
index 407ecf78a..108e0db56 100644
--- a/data/tariffplans/testit/Filters.csv
+++ b/data/tariffplans/testit/Filters.csv
@@ -6,6 +6,7 @@ cgrates.org,FLTR_1,*prefix,Destination,10;20,
cgrates.org,FLTR_1,*rsr,,Subject(~^1.*1$);Destination(1002),
cgrates.org,FLTR_ACNT_1007,*string,Account,1007,2014-07-29T15:00:00Z
cgrates.org,FLTR_ACNT_dan,*string,Account,dan,2014-07-29T15:00:00Z
+cgrates.org,FLTR_SPP_ACNT_dan,*string,*req.Account,dan,2014-07-29T15:00:00Z
cgrates.org,FLTR_SPP_2,*string,Account,1003;1002,2014-07-29T15:00:00Z
cgrates.org,FLTR_SPP_2,*prefix,Destination,10;20,
cgrates.org,FLTR_SPP_2,*rsr,,Subject(~^1.*1$);Destination(1002),
@@ -16,4 +17,8 @@ cgrates.org,FLTR_STAT_2,*string,Account,1002,2014-07-29T15:00:00Z
cgrates.org,FLTR_STAT_3,*string,Account,1003,2014-07-29T15:00:00Z
cgrates.org,FLTR_SPP_4,*string,DistincMatch,*qos2,2014-07-29T15:00:00Z
cgrates.org,FLTR_SPP_5,*string,DistincMatch,*qos3,2014-07-29T15:00:00Z
-cgrates.org,FLTR_STAT_1_1,*string,Stat,Stat1_1,2014-07-29T15:00:00Z
\ No newline at end of file
+cgrates.org,FLTR_STAT_1_1,*string,Stat,Stat1_1,2014-07-29T15:00:00Z
+cgrates.org,FLTR_SPP_6,*string,DistincMatch,*qos_filtred,2014-07-29T15:00:00Z
+cgrates.org,FLTR_QOS_SP1,*gte,*gs.*acd,10.0,2014-07-29T15:00:00Z
+cgrates.org,FLTR_QOS_SP2,*gte,*gs.*acd,10.0,2014-07-29T15:00:00Z
+cgrates.org,FLTR_QOS_SP2,*gte,*gs.*tcd,11.0,
\ No newline at end of file
diff --git a/data/tariffplans/testit/Suppliers.csv b/data/tariffplans/testit/Suppliers.csv
index 0fb932afe..f9c95a2e5 100644
--- a/data/tariffplans/testit/Suppliers.csv
+++ b/data/tariffplans/testit/Suppliers.csv
@@ -4,7 +4,7 @@ cgrates.org,SPL_ACNT_1001,,,,,supplier2,,,,,,10,,,
cgrates.org,SPL_WEIGHT_2,,2017-11-27T00:00:00Z,*weight,,supplier1,,,,,,10,,,5
cgrates.org,SPL_WEIGHT_1,FLTR_DST_DE;FLTR_ACNT_1007,2017-11-27T00:00:00Z,*weight,,supplier1,,,,,,10,,,10
cgrates.org,SPL_WEIGHT_1,FLTR_DST_DE,,,,supplier2,,,,,,20,,,
-cgrates.org,SPL_WEIGHT_1,FLTR_ACNT_1007,,,,supplier3,FLTR_ACNT_dan,,,,,15,,,
+cgrates.org,SPL_WEIGHT_1,FLTR_ACNT_1007,,,,supplier3,FLTR_SPP_ACNT_dan,,,,,15,,,
cgrates.org,SPL_LEASTCOST_1,FLTR_1,2017-11-27T00:00:00Z,*least_cost,,supplier1,,,RP_SPECIAL_1002,,,10,false,,10
cgrates.org,SPL_LEASTCOST_1,,,,,supplier2,,,RP_RETAIL1,,,20,,,
cgrates.org,SPL_LEASTCOST_1,,,,,supplier3,,,RP_SPECIAL_1002,,,15,,,
@@ -20,3 +20,6 @@ cgrates.org,SPL_QOS_2,,,,,supplier3,,,,,Stat_3,35,,,
cgrates.org,SPL_QOS_3,FLTR_SPP_5,2017-11-27T00:00:00Z,*qos,*pdd,supplier1,,,,,Stat_1;Stat_1_1,10,false,,10
cgrates.org,SPL_QOS_3,,,,,supplier2,,,,,Stat_2,20,,,
cgrates.org,SPL_QOS_3,,,,,supplier3,,,,,Stat_3,35,,,
+cgrates.org,SPL_QOS_FILTRED,FLTR_SPP_6,2017-11-27T00:00:00Z,*qos,*pdd,supplier1,FLTR_QOS_SP1,,,,Stat_1;Stat_1_1,10,false,,10
+cgrates.org,SPL_QOS_FILTRED,,,,,supplier2,FLTR_QOS_SP2,,,,Stat_2,20,,,
+cgrates.org,SPL_QOS_FILTRED,,,,,supplier3,,,,,Stat_3,35,,,
diff --git a/engine/libsuppliers.go b/engine/libsuppliers.go
index e937f6a4e..67342098b 100644
--- a/engine/libsuppliers.go
+++ b/engine/libsuppliers.go
@@ -31,7 +31,7 @@ type SortedSupplier struct {
SupplierID string
SupplierParameters string
SortingData map[string]interface{} // store here extra info like cost or stats
- worstStats map[string]float64
+ globalStats map[string]float64
}
// SuppliersReply is returned as part of GetSuppliers call
@@ -97,21 +97,21 @@ func (sSpls *SortedSuppliers) SortQOS(params []string) {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
for _, param := range params {
// skip to next param
- if sSpls.SortedSuppliers[i].worstStats[param] == sSpls.SortedSuppliers[j].worstStats[param] {
+ if sSpls.SortedSuppliers[i].globalStats[param] == sSpls.SortedSuppliers[j].globalStats[param] {
continue
}
- if (param != utils.MetaPDD && sSpls.SortedSuppliers[i].worstStats[param] == -1) ||
- (param == utils.MetaPDD && sSpls.SortedSuppliers[i].worstStats[param] == 1000000) {
+ if (param != utils.MetaPDD && sSpls.SortedSuppliers[i].globalStats[param] == -1) ||
+ (param == utils.MetaPDD && sSpls.SortedSuppliers[i].globalStats[param] == 1000000) {
return false
}
switch param {
default:
- return sSpls.SortedSuppliers[i].worstStats[param] > sSpls.SortedSuppliers[j].worstStats[param]
+ return sSpls.SortedSuppliers[i].globalStats[param] > sSpls.SortedSuppliers[j].globalStats[param]
case utils.MetaPDD:
- return sSpls.SortedSuppliers[i].worstStats[param] < sSpls.SortedSuppliers[j].worstStats[param]
+ return sSpls.SortedSuppliers[i].globalStats[param] < sSpls.SortedSuppliers[j].globalStats[param]
}
}
- return sSpls.SortedSuppliers[i].worstStats[utils.Weight] > sSpls.SortedSuppliers[j].worstStats[utils.Weight]
+ return sSpls.SortedSuppliers[i].globalStats[utils.Weight] > sSpls.SortedSuppliers[j].globalStats[utils.Weight]
})
}
@@ -134,7 +134,7 @@ type SuppliersSorter interface {
// NewSupplierSortDispatcher constructs SupplierSortDispatcher
func NewSupplierSortDispatcher(lcrS *SupplierService) (ssd SupplierSortDispatcher, err error) {
ssd = make(map[string]SuppliersSorter)
- ssd[utils.MetaWeight] = NewWeightSorter()
+ ssd[utils.MetaWeight] = NewWeightSorter(lcrS)
ssd[utils.MetaLeastCost] = NewLeastCostSorter(lcrS)
ssd[utils.MetaHighestCost] = NewHighestCostSorter(lcrS)
ssd[utils.MetaQOS] = NewQOSSupplierSorter(lcrS)
@@ -153,27 +153,3 @@ func (ssd SupplierSortDispatcher) SortSuppliers(prflID, strategy string,
}
return sd.SortSuppliers(prflID, suppls, suplEv, extraOpts)
}
-
-func NewWeightSorter() *WeightSorter {
- return &WeightSorter{sorting: utils.MetaWeight}
-}
-
-// WeightSorter orders suppliers based on their weight, no cost involved
-type WeightSorter struct {
- sorting string
-}
-
-func (ws *WeightSorter) SortSuppliers(prflID string,
- suppls []*Supplier, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
- sortedSuppls = &SortedSuppliers{ProfileID: prflID,
- Sorting: ws.sorting,
- SortedSuppliers: make([]*SortedSupplier, len(suppls))}
- for i, s := range suppls {
- sortedSuppls.SortedSuppliers[i] = &SortedSupplier{
- SupplierID: s.ID,
- SortingData: map[string]interface{}{utils.Weight: s.Weight},
- SupplierParameters: s.SupplierParameters}
- }
- sortedSuppls.SortWeight()
- return
-}
diff --git a/engine/libsuppliers_test.go b/engine/libsuppliers_test.go
index 370b811f6..4dac55fec 100644
--- a/engine/libsuppliers_test.go
+++ b/engine/libsuppliers_test.go
@@ -89,64 +89,60 @@ func TestLibSuppliersSortCost(t *testing.T) {
}
func TestLibSuppliersSortWeight(t *testing.T) {
- spl := []*Supplier{
- &Supplier{
- ID: "supplier1",
- FilterIDs: []string{},
- AccountIDs: []string{},
- RatingPlanIDs: []string{},
- ResourceIDs: []string{},
- StatIDs: []string{},
- Weight: 10.0,
- SupplierParameters: "param1",
- },
- &Supplier{
- ID: "supplier2",
- FilterIDs: []string{},
- AccountIDs: []string{},
- RatingPlanIDs: []string{},
- ResourceIDs: []string{},
- StatIDs: []string{},
- Weight: 20.0,
- SupplierParameters: "param2",
- },
- }
- eSpls := SortedSuppliers{
- ProfileID: "SPL_WEIGHT_1",
- Sorting: utils.MetaWeight,
+ sSpls := &SortedSuppliers{
SortedSuppliers: []*SortedSupplier{
+ &SortedSupplier{
+ SupplierID: "supplier1",
+ SortingData: map[string]interface{}{
+ utils.Weight: 10.0,
+ },
+ SupplierParameters: "param1",
+ },
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
- "Weight": 20.0,
+ utils.Weight: 20.0,
},
SupplierParameters: "param2",
},
+ &SortedSupplier{
+ SupplierID: "supplier3",
+ SortingData: map[string]interface{}{
+ utils.Weight: 10.5,
+ },
+ SupplierParameters: "param3",
+ },
+ },
+ }
+ sSpls.SortWeight()
+ eOrderedSpls := &SortedSuppliers{
+ SortedSuppliers: []*SortedSupplier{
+ &SortedSupplier{
+ SupplierID: "supplier2",
+ SortingData: map[string]interface{}{
+ utils.Weight: 20.0,
+ },
+ SupplierParameters: "param2",
+ },
+ &SortedSupplier{
+ SupplierID: "supplier3",
+ SortingData: map[string]interface{}{
+ utils.Weight: 10.5,
+ },
+ SupplierParameters: "param3",
+ },
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
- "Weight": 10.0,
+ utils.Weight: 10.0,
},
SupplierParameters: "param1",
},
},
}
- se := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "supplierevent1",
- Event: make(map[string]interface{}),
- }
- ws := NewWeightSorter()
- result, err := ws.SortSuppliers("SPL_WEIGHT_1", spl, se, nil)
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(eSpls.ProfileID, result.ProfileID) {
- t.Errorf("Expecting: %+v, received: %+v", eSpls.ProfileID, result.ProfileID)
- } else if !reflect.DeepEqual(eSpls.SortedSuppliers, result.SortedSuppliers) {
- t.Errorf("Expecting: %+v, received: %+v", eSpls.SortedSuppliers, result.SortedSuppliers)
- } else if !reflect.DeepEqual(eSpls.Sorting, result.Sorting) {
- t.Errorf("Expecting: %+v, received: %+v", eSpls.Sorting, result.Sorting)
+ if !reflect.DeepEqual(eOrderedSpls, sSpls) {
+ t.Errorf("Expecting: %s, received: %s",
+ utils.ToJSON(eOrderedSpls), utils.ToJSON(sSpls))
}
}
@@ -288,7 +284,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 15.0,
},
@@ -296,7 +292,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
},
@@ -304,7 +300,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.05,
utils.MetaTCD: 10.0,
},
@@ -317,7 +313,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
},
@@ -325,7 +321,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 15.0,
},
@@ -333,7 +329,7 @@ func TestLibSuppliersSortQOS(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.05,
utils.MetaTCD: 10.0,
},
@@ -352,7 +348,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
},
@@ -360,7 +356,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
},
@@ -368,7 +364,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
},
@@ -381,7 +377,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
},
@@ -389,7 +385,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
},
@@ -397,7 +393,7 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
},
@@ -416,7 +412,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: 1.2,
@@ -425,7 +421,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: -1.0,
@@ -434,7 +430,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
@@ -448,7 +444,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: 1.2,
@@ -457,7 +453,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
@@ -466,7 +462,7 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: -1.0,
@@ -486,7 +482,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: -1.0,
@@ -496,7 +492,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: 1.2,
@@ -506,7 +502,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
@@ -521,7 +517,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: 1.2,
@@ -531,7 +527,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
@@ -541,7 +537,7 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: -1.0,
@@ -562,7 +558,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaPDD: 0.5,
},
@@ -570,7 +566,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaPDD: 0.6,
},
@@ -578,7 +574,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaPDD: 0.2,
},
@@ -591,7 +587,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.MetaPDD: 0.2,
},
@@ -599,7 +595,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaPDD: 0.5,
},
@@ -607,7 +603,7 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.MetaPDD: 0.6,
},
@@ -626,7 +622,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.Weight: 15.0,
},
@@ -634,7 +630,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.Weight: 25.0,
},
@@ -642,7 +638,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.Weight: 20.0,
},
@@ -655,7 +651,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
SupplierID: "supplier2",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.Weight: 25.0,
},
@@ -663,7 +659,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
},
&SortedSupplier{
SupplierID: "supplier1",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.2,
utils.Weight: 15.0,
},
@@ -672,7 +668,7 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier3",
- worstStats: map[string]float64{
+ globalStats: map[string]float64{
utils.MetaACD: 0.1,
utils.Weight: 20.0,
},
diff --git a/engine/spls_highestcost.go b/engine/spls_highestcost.go
index c2f5bc767..82afdd49e 100755
--- a/engine/spls_highestcost.go
+++ b/engine/spls_highestcost.go
@@ -19,8 +19,6 @@ along with this program. If not, see
package engine
import (
- "fmt"
-
"github.com/cgrates/cgrates/utils"
)
@@ -35,42 +33,17 @@ type HightCostSorter struct {
spS *SupplierService
}
-func (lcs *HightCostSorter) SortSuppliers(prflID string, suppls []*Supplier,
+func (hcs *HightCostSorter) SortSuppliers(prflID string, suppls []*Supplier,
ev *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
sortedSuppls = &SortedSuppliers{ProfileID: prflID,
- Sorting: lcs.sorting,
+ Sorting: hcs.sorting,
SortedSuppliers: make([]*SortedSupplier, 0)}
for _, s := range suppls {
- costData, err := lcs.spS.costForEvent(ev, s.AccountIDs, s.RatingPlanIDs)
- if err != nil {
- if extraOpts.ignoreErrors {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, err: %s",
- utils.SupplierS, prflID, s.ID, err.Error()))
- continue
- }
+ if srtSpl, pass, err := hcs.spS.populateSortingData(ev, s, extraOpts); err != nil {
return nil, err
- } else if len(costData) == 0 {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, missing cost information",
- utils.SupplierS, prflID, s.ID))
- continue
+ } else if pass && srtSpl != nil {
+ sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers, srtSpl)
}
- if extraOpts.maxCost != 0 &&
- costData[utils.Cost].(float64) > extraOpts.maxCost {
- continue
- }
- srtData := map[string]interface{}{
- utils.Weight: s.Weight,
- }
- for k, v := range costData {
- srtData[k] = v
- }
- sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers,
- &SortedSupplier{
- SupplierID: s.ID,
- SortingData: srtData,
- SupplierParameters: s.SupplierParameters})
}
if len(sortedSuppls.SortedSuppliers) == 0 {
return nil, utils.ErrNotFound
diff --git a/engine/spls_leastcost.go b/engine/spls_leastcost.go
index 94c5cca78..5d5d386cc 100644
--- a/engine/spls_leastcost.go
+++ b/engine/spls_leastcost.go
@@ -19,8 +19,6 @@ along with this program. If not, see
package engine
import (
- "fmt"
-
"github.com/cgrates/cgrates/utils"
)
@@ -41,36 +39,11 @@ func (lcs *LeastCostSorter) SortSuppliers(prflID string, suppls []*Supplier,
Sorting: lcs.sorting,
SortedSuppliers: make([]*SortedSupplier, 0)}
for _, s := range suppls {
- costData, err := lcs.spS.costForEvent(ev, s.AccountIDs, s.RatingPlanIDs)
- if err != nil {
- if extraOpts.ignoreErrors {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, err: %s",
- utils.SupplierS, prflID, s.ID, err.Error()))
- continue
- }
+ if srtSpl, pass, err := lcs.spS.populateSortingData(ev, s, extraOpts); err != nil {
return nil, err
- } else if len(costData) == 0 {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, missing cost information",
- utils.SupplierS, prflID, s.ID))
- continue
+ } else if pass && srtSpl != nil {
+ sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers, srtSpl)
}
- if extraOpts.maxCost != 0 &&
- costData[utils.Cost].(float64) > extraOpts.maxCost {
- continue
- }
- srtData := map[string]interface{}{
- utils.Weight: s.Weight,
- }
- for k, v := range costData {
- srtData[k] = v
- }
- sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers,
- &SortedSupplier{
- SupplierID: s.ID,
- SortingData: srtData,
- SupplierParameters: s.SupplierParameters})
}
if len(sortedSuppls.SortedSuppliers) == 0 {
return nil, utils.ErrNotFound
diff --git a/engine/spls_qos.go b/engine/spls_qos.go
index d520aab68..e82017c38 100755
--- a/engine/spls_qos.go
+++ b/engine/spls_qos.go
@@ -19,9 +19,6 @@ along with this program. If not, see
package engine
import (
- "fmt"
- "strings"
-
"github.com/cgrates/cgrates/utils"
)
@@ -36,62 +33,17 @@ type QOSSupplierSorter struct {
spS *SupplierService
}
-func (lcs *QOSSupplierSorter) SortSuppliers(prflID string, suppls []*Supplier,
+func (qos *QOSSupplierSorter) SortSuppliers(prflID string, suppls []*Supplier,
ev *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
sortedSuppls = &SortedSuppliers{ProfileID: prflID,
- Sorting: lcs.sorting,
+ Sorting: qos.sorting,
SortedSuppliers: make([]*SortedSupplier, 0)}
for _, s := range suppls {
- metricSupp, err := lcs.spS.statMetrics(s.StatIDs, ev.Tenant) //create metric map for suppier s
- if err != nil {
- if extraOpts.ignoreErrors {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, err: %s",
- utils.SupplierS, prflID, s.ID, err.Error()))
- continue
- }
+ if srtSpl, pass, err := qos.spS.populateSortingData(ev, s, extraOpts); err != nil {
return nil, err
+ } else if pass && srtSpl != nil {
+ sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers, srtSpl)
}
-
- srtData := map[string]float64{
- utils.Weight: s.Weight,
- }
- for _, metric := range extraOpts.sortingParameters {
- hasMetric := false //check if metricSupp have sortingParameter
- for keyWithID, value := range metricSupp { //transfer data from metric into srtData
- if metric == strings.Split(keyWithID, utils.InInFieldSep)[0] {
- if val, hasKey := srtData[metric]; !hasKey ||
- (metric == utils.MetaPDD && val < value) || //worst values
- (metric != utils.MetaPDD && val > value) {
- srtData[metric] = value
- hasMetric = true
- }
- }
- }
- if !hasMetric { //if not have populate with default value
- switch metric {
- default:
- srtData[metric] = -1
- case utils.MetaPDD:
- srtData[metric] = 1000000
- }
- }
- }
-
- sortingData := map[string]interface{}{
- utils.Weight: s.Weight,
- }
- for k, v := range metricSupp {
- sortingData[k] = v
- }
- sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers,
- &SortedSupplier{
- SupplierID: s.ID,
- SortingData: sortingData,
- SupplierParameters: s.SupplierParameters,
- worstStats: srtData,
- },
- )
}
if len(sortedSuppls.SortedSuppliers) == 0 {
return nil, utils.ErrNotFound
diff --git a/engine/spls_weight.go b/engine/spls_weight.go
new file mode 100755
index 000000000..6cc518a24
--- /dev/null
+++ b/engine/spls_weight.go
@@ -0,0 +1,50 @@
+/*
+Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
+Copyright (C) ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package engine
+
+import (
+ "github.com/cgrates/cgrates/utils"
+)
+
+func NewWeightSorter(spS *SupplierService) *WeightSorter {
+ return &WeightSorter{spS: spS,
+ sorting: utils.MetaWeight}
+}
+
+// WeightSorter orders suppliers based on their weight, no cost involved
+type WeightSorter struct {
+ sorting string
+ spS *SupplierService
+}
+
+func (ws *WeightSorter) SortSuppliers(prflID string,
+ suppls []*Supplier, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
+ sortedSuppls = &SortedSuppliers{ProfileID: prflID,
+ Sorting: ws.sorting,
+ SortedSuppliers: make([]*SortedSupplier, 0)}
+ for _, s := range suppls {
+ if srtSpl, pass, err := ws.spS.populateSortingData(suplEv, s, extraOpts); err != nil {
+ return nil, err
+ } else if pass && srtSpl != nil {
+ sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers, srtSpl)
+ }
+ }
+ sortedSuppls.SortWeight()
+ return
+}
diff --git a/engine/suppliers.go b/engine/suppliers.go
index 884f1efcb..51fe63206 100644
--- a/engine/suppliers.go
+++ b/engine/suppliers.go
@@ -23,6 +23,7 @@ import (
"reflect"
"sort"
"strconv"
+ "strings"
"time"
"github.com/cgrates/cgrates/config"
@@ -284,6 +285,100 @@ func (spS *SupplierService) resourceUsage(resIDs []string) (tUsage float64, err
return
}
+func (spS *SupplierService) populateSortingData(ev *utils.CGREvent, spl *Supplier, extraOpts *optsGetSuppliers) (srtSpl *SortedSupplier, pass bool, err error) {
+ globalStats := map[string]float64{ //used for QOS strategy
+ utils.Weight: spl.Weight,
+ }
+ sortedSpl := &SortedSupplier{
+ SupplierID: spl.ID,
+ SortingData: map[string]interface{}{
+ utils.Weight: spl.Weight,
+ },
+ SupplierParameters: spl.SupplierParameters,
+ }
+ //calculate costData if we have fields
+ if len(spl.AccountIDs) != 0 || len(spl.RatingPlanIDs) != 0 {
+ costData, err := spS.costForEvent(ev, spl.AccountIDs, spl.RatingPlanIDs)
+ if err != nil {
+ if extraOpts.ignoreErrors {
+ utils.Logger.Warning(
+ fmt.Sprintf("<%s> ignoring supplier with ID: %s, err: %s",
+ utils.SupplierS, spl.ID, err.Error()))
+ } else {
+ return nil, false, err
+ }
+ } else if len(costData) == 0 {
+ utils.Logger.Warning(
+ fmt.Sprintf("<%s> profile: %s ignoring supplier with ID: %s, missing cost information",
+ utils.SupplierS, spl.ID))
+ } else {
+ if extraOpts.maxCost != 0 &&
+ costData[utils.Cost].(float64) > extraOpts.maxCost {
+ return nil, false, nil
+ }
+ for k, v := range costData {
+ sortedSpl.SortingData[k] = v
+ }
+ }
+ }
+ metricForFilter := map[string]interface{}{
+ utils.Weight: spl.Weight,
+ }
+ //calculate metrics
+ if len(spl.StatIDs) != 0 {
+ metricSupp, err := spS.statMetrics(spl.StatIDs, ev.Tenant) //create metric map for suppier
+ if err != nil {
+ if extraOpts.ignoreErrors {
+ utils.Logger.Warning(
+ fmt.Sprintf("<%s> ignoring supplier with ID: %s, err: %s",
+ utils.SupplierS, spl.ID, err.Error()))
+ } else {
+ return nil, false, err
+ }
+ }
+ for _, metric := range extraOpts.sortingParameters {
+ hasMetric := false //check if metricSupp have sortingParameter
+ for keyWithID, value := range metricSupp { //transfer data from metric into globalStats
+ if metric == strings.Split(keyWithID, utils.InInFieldSep)[0] {
+ if val, hasKey := globalStats[metric]; !hasKey ||
+ (metric == utils.MetaPDD && val < value) || //worst values
+ (metric != utils.MetaPDD && val > value) {
+ globalStats[metric] = value
+ hasMetric = true
+ }
+ }
+ }
+ if !hasMetric { //if not have populate with default value
+ switch metric {
+ default:
+ globalStats[metric] = -1
+ case utils.MetaPDD:
+ globalStats[metric] = 1000000
+ }
+ }
+ }
+ for k, v := range metricSupp {
+ sortedSpl.SortingData[k] = v
+ metricForFilter[strings.Split(k, utils.InInFieldSep)[0]] = v
+ }
+ sortedSpl.globalStats = globalStats
+ }
+ //filter the supplier
+ if len(spl.FilterIDs) != 0 {
+ nM := NewNavigableMap(nil)
+ nM.Set([]string{"*req"}, ev.Event, false)
+ nM.Set([]string{"*sd"}, sortedSpl.SortingData, false)
+ nM.Set([]string{"*gs"}, metricForFilter, false)
+ if pass, err = spS.filterS.Pass(ev.Tenant, spl.FilterIDs,
+ nM); err != nil {
+ return nil, false, err
+ } else if !pass {
+ return nil, false, nil
+ }
+ }
+ return sortedSpl, true, nil
+}
+
// supliersForEvent will return the list of valid supplier IDs
// for event based on filters and sorting algorithms
func (spS *SupplierService) sortedSuppliersForEvent(args *ArgsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
@@ -296,40 +391,36 @@ func (spS *SupplierService) sortedSuppliersForEvent(args *ArgsGetSuppliers) (sor
} else if len(suppPrfls) == 0 {
return nil, utils.ErrNotFound
}
- splPrfl := suppPrfls[0] // pick up the first lcr profile as winner
- var spls []*Supplier
- for _, s := range splPrfl.Suppliers {
- if len(s.FilterIDs) != 0 { // filters should be applied, check them here
- if pass, err := spS.filterS.Pass(args.Tenant, s.FilterIDs,
- NewNavigableMap(args.Event)); err != nil {
- return nil, err
- } else if !pass {
- continue
- }
- }
- spls = append(spls, s)
- }
+ splPrfl := suppPrfls[0] // pick up the first lcr profile as winner
extraOpts, err := args.asOptsGetSuppliers() // convert suppliers arguments into internal options used to limit data
if err != nil {
return nil, err
}
extraOpts.sortingParameters = splPrfl.SortingParameters // populate sortingParameters in extraOpts
sortedSuppliers, err := spS.sorter.SortSuppliers(splPrfl.ID, splPrfl.Sorting,
- spls, &args.CGREvent, extraOpts)
+ splPrfl.Suppliers, &args.CGREvent, extraOpts)
if err != nil {
return nil, err
}
+ srtTmp := &SortedSuppliers{
+ ProfileID: sortedSuppliers.ProfileID,
+ Sorting: sortedSuppliers.Sorting,
+ }
+ for _, s := range sortedSuppliers.SortedSuppliers {
+
+ srtTmp.SortedSuppliers = append(srtTmp.SortedSuppliers, s)
+ }
if args.Paginator.Offset != nil {
- if *args.Paginator.Offset <= len(sortedSuppliers.SortedSuppliers) {
- sortedSuppliers.SortedSuppliers = sortedSuppliers.SortedSuppliers[*args.Paginator.Offset:]
+ if *args.Paginator.Offset <= len(srtTmp.SortedSuppliers) {
+ srtTmp.SortedSuppliers = srtTmp.SortedSuppliers[*args.Paginator.Offset:]
}
}
if args.Paginator.Limit != nil {
- if *args.Paginator.Limit <= len(sortedSuppliers.SortedSuppliers) {
- sortedSuppliers.SortedSuppliers = sortedSuppliers.SortedSuppliers[:*args.Paginator.Limit]
+ if *args.Paginator.Limit <= len(srtTmp.SortedSuppliers) {
+ srtTmp.SortedSuppliers = srtTmp.SortedSuppliers[:*args.Paginator.Limit]
}
}
- return sortedSuppliers, nil
+ return srtTmp, nil
}
type ArgsGetSuppliers struct {
diff --git a/engine/suppliers_test.go b/engine/suppliers_test.go
index 88dd79915..ca3cc7bde 100644
--- a/engine/suppliers_test.go
+++ b/engine/suppliers_test.go
@@ -45,7 +45,7 @@ var (
Suppliers: []*Supplier{
&Supplier{
ID: "supplier1",
- FilterIDs: []string{"FLTR_SUPP_1"},
+ FilterIDs: []string{},
AccountIDs: []string{},
RatingPlanIDs: []string{},
ResourceIDs: []string{},
@@ -70,7 +70,7 @@ var (
Suppliers: []*Supplier{
&Supplier{
ID: "supplier2",
- FilterIDs: []string{"FLTR_SUPP_2"},
+ FilterIDs: []string{},
AccountIDs: []string{},
RatingPlanIDs: []string{},
ResourceIDs: []string{},
@@ -80,7 +80,7 @@ var (
},
&Supplier{
ID: "supplier3",
- FilterIDs: []string{"FLTR_SUPP_2"},
+ FilterIDs: []string{},
AccountIDs: []string{},
RatingPlanIDs: []string{},
ResourceIDs: []string{},
@@ -90,7 +90,7 @@ var (
},
&Supplier{
ID: "supplier1",
- FilterIDs: []string{"FLTR_SUPP_2"},
+ FilterIDs: []string{},
AccountIDs: []string{},
RatingPlanIDs: []string{},
ResourceIDs: []string{},
@@ -115,7 +115,7 @@ var (
Suppliers: []*Supplier{
&Supplier{
ID: "supplier1",
- FilterIDs: []string{"FLTR_SUPP_3"},
+ FilterIDs: []string{},
AccountIDs: []string{},
RatingPlanIDs: []string{},
ResourceIDs: []string{},
@@ -430,6 +430,7 @@ func TestSuppliersSortedForEvent(t *testing.T) {
if !reflect.DeepEqual(eFirstSupplierProfile, sprf) {
t.Errorf("Expecting: %+v, received: %+v", eFirstSupplierProfile, sprf)
}
+
eFirstSupplierProfile = &SortedSuppliers{
ProfileID: "SupplierProfile2",
Sorting: utils.MetaWeight,
diff --git a/utils/apitpdata.go b/utils/apitpdata.go
index 16f36d64e..9f0b7f9fa 100755
--- a/utils/apitpdata.go
+++ b/utils/apitpdata.go
@@ -1386,6 +1386,7 @@ type TPFilter struct {
type TPSupplier struct {
ID string // SupplierID
+ SortingFilter []string
FilterIDs []string
AccountIDs []string
RatingPlanIDs []string // used when computing price
diff --git a/utils/consts.go b/utils/consts.go
index 26e10e2c1..d97906461 100755
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -486,6 +486,7 @@ const (
MetaLeastCost = "*least_cost"
MetaHighestCost = "*highest_cost"
MetaQOS = "*qos"
+ MetaStatFiltered = "*stat_filtered"
Weight = "Weight"
Cost = "Cost"
RatingPlanID = "RatingPlanID"