mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Add FilterIDs, Weights & Blockers functionality to set/remove balance action types
This commit is contained in:
committed by
Dan Christian Bogos
parent
076dd821a9
commit
9fa6844fae
@@ -19,7 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package actions
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/cgrates/birpc/context"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
@@ -31,6 +33,7 @@ import (
|
||||
type actSetBalance struct {
|
||||
config *config.CGRConfig
|
||||
connMgr *engine.ConnManager
|
||||
fltrS *engine.FilterS
|
||||
aCfg *utils.APAction
|
||||
tnt string
|
||||
reset bool
|
||||
@@ -50,14 +53,36 @@ func (aL *actSetBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
return fmt.Errorf("no connection with AccountS")
|
||||
}
|
||||
|
||||
weights := make(map[string]float64) // stores sorting weights by Diktat ID
|
||||
diktats := make([]*utils.APDiktat, 0) // list of diktats which have *balancePath in opts, will be weight sorted later
|
||||
for _, diktat := range aL.cfg().Diktats {
|
||||
if _, has := diktat.Opts[utils.MetaBalancePath]; !has {
|
||||
continue
|
||||
}
|
||||
if pass, err := aL.fltrS.Pass(ctx, aL.tnt, diktat.FilterIDs, data); err != nil {
|
||||
return err
|
||||
} else if !pass {
|
||||
continue
|
||||
}
|
||||
weight, err := engine.WeightFromDynamics(ctx, diktat.Weights, aL.fltrS, aL.tnt, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
weights[diktat.ID] = weight
|
||||
diktats = append(diktats, diktat)
|
||||
}
|
||||
// Sort by weight (higher values first).
|
||||
slices.SortFunc(diktats, func(a, b *utils.APDiktat) int {
|
||||
return cmp.Compare(weights[b.ID], weights[a.ID])
|
||||
})
|
||||
args := &utils.ArgsActSetBalance{
|
||||
Tenant: aL.tnt,
|
||||
AccountID: trgID,
|
||||
Reset: aL.reset,
|
||||
Diktats: make([]*utils.BalDiktat, len(aL.cfg().Diktats)),
|
||||
Diktats: make([]*utils.BalDiktat, 0),
|
||||
APIOpts: aL.cfg().Opts,
|
||||
}
|
||||
for i, actD := range aL.cfg().Diktats {
|
||||
for _, actD := range diktats {
|
||||
var rsr utils.RSRParsers
|
||||
if rsr, err = actD.RSRValues(); err != nil {
|
||||
return
|
||||
@@ -66,9 +91,14 @@ func (aL *actSetBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
if val, err = rsr.ParseDataProvider(data); err != nil {
|
||||
return
|
||||
}
|
||||
args.Diktats[i] = &utils.BalDiktat{
|
||||
args.Diktats = append(args.Diktats, &utils.BalDiktat{
|
||||
Path: utils.IfaceAsString(actD.Opts[utils.MetaBalancePath]),
|
||||
Value: val,
|
||||
})
|
||||
if blocker, err := engine.BlockerFromDynamics(ctx, actD.Blockers, aL.fltrS, aL.tnt, data); err != nil {
|
||||
return err
|
||||
} else if blocker {
|
||||
break
|
||||
}
|
||||
}
|
||||
var rply string
|
||||
@@ -80,6 +110,7 @@ func (aL *actSetBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
type actRemBalance struct {
|
||||
config *config.CGRConfig
|
||||
connMgr *engine.ConnManager
|
||||
fltrS *engine.FilterS
|
||||
aCfg *utils.APAction
|
||||
tnt string
|
||||
}
|
||||
@@ -98,14 +129,41 @@ func (aL *actRemBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
return fmt.Errorf("no connection with AccountS")
|
||||
}
|
||||
|
||||
weights := make(map[string]float64) // stores sorting weights by Diktat ID
|
||||
diktats := make([]*utils.APDiktat, 0) // list of diktats which have *balancePath in opts, will be weight sorted later
|
||||
for _, diktat := range aL.cfg().Diktats {
|
||||
if _, has := diktat.Opts[utils.MetaBalancePath]; !has {
|
||||
continue
|
||||
}
|
||||
if pass, err := aL.fltrS.Pass(ctx, aL.tnt, diktat.FilterIDs, data); err != nil {
|
||||
return err
|
||||
} else if !pass {
|
||||
continue
|
||||
}
|
||||
weight, err := engine.WeightFromDynamics(ctx, diktat.Weights, aL.fltrS, aL.tnt, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
weights[diktat.ID] = weight
|
||||
diktats = append(diktats, diktat)
|
||||
}
|
||||
// Sort by weight (higher values first).
|
||||
slices.SortFunc(diktats, func(a, b *utils.APDiktat) int {
|
||||
return cmp.Compare(weights[b.ID], weights[a.ID])
|
||||
})
|
||||
args := &utils.ArgsActRemoveBalances{
|
||||
Tenant: aL.tnt,
|
||||
AccountID: trgID,
|
||||
BalanceIDs: make([]string, len(aL.cfg().Diktats)),
|
||||
BalanceIDs: make([]string, len(diktats)),
|
||||
APIOpts: aL.cfg().Opts,
|
||||
}
|
||||
for i, actD := range aL.cfg().Diktats {
|
||||
for i, actD := range diktats {
|
||||
args.BalanceIDs[i] = utils.IfaceAsString(actD.Opts[utils.MetaBalancePath])
|
||||
if blocker, err := engine.BlockerFromDynamics(ctx, actD.Blockers, aL.fltrS, aL.tnt, data); err != nil {
|
||||
return err
|
||||
} else if blocker {
|
||||
break
|
||||
}
|
||||
}
|
||||
var rply string
|
||||
return aL.connMgr.Call(ctx, aL.config.ActionSCfg().AccountSConns,
|
||||
|
||||
@@ -101,9 +101,14 @@ func TestACExecuteAccountsRemBalance(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
idb, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actRemBal := &actRemBalance{
|
||||
config: cfg,
|
||||
connMgr: connMngr,
|
||||
fltrS: engine.NewFilterS(cfg, connMngr, engine.NewDataManager(idb, cfg, connMngr)),
|
||||
aCfg: apAction,
|
||||
tnt: "cgrates.org",
|
||||
}
|
||||
|
||||
@@ -132,11 +132,11 @@ func newActioner(ctx *context.Context, cgrEv *utils.CGREvent, cfg *config.CGRCon
|
||||
case utils.MetaResetThreshold:
|
||||
return &actResetThreshold{tnt, cfg, connMgr, aCfg}, nil
|
||||
case utils.MetaAddBalance:
|
||||
return &actSetBalance{cfg, connMgr, aCfg, tnt, false}, nil
|
||||
return &actSetBalance{cfg, connMgr, fltrS, aCfg, tnt, false}, nil
|
||||
case utils.MetaSetBalance:
|
||||
return &actSetBalance{cfg, connMgr, aCfg, tnt, true}, nil
|
||||
return &actSetBalance{cfg, connMgr, fltrS, aCfg, tnt, true}, nil
|
||||
case utils.MetaRemBalance:
|
||||
return &actRemBalance{cfg, connMgr, aCfg, tnt}, nil
|
||||
return &actRemBalance{cfg, connMgr, fltrS, aCfg, tnt}, nil
|
||||
case utils.MetaDynamicThreshold:
|
||||
return &actDynamicThreshold{cfg, connMgr, fltrS, aCfg, tnt, cgrEv}, nil
|
||||
case utils.MetaDynamicStats:
|
||||
|
||||
@@ -70,9 +70,9 @@ func TestACExecuteCDRLog(t *testing.T) {
|
||||
&actExport{"cgrates.org", cfg, nil, &utils.APAction{Type: utils.MetaExport}},
|
||||
&actResetStat{"cgrates.org", cfg, nil, &utils.APAction{Type: utils.MetaResetStatQueue}},
|
||||
&actResetThreshold{"cgrates.org", cfg, nil, &utils.APAction{Type: utils.MetaResetThreshold}},
|
||||
&actSetBalance{cfg, nil, &utils.APAction{Type: utils.MetaAddBalance}, "cgrates.org", false},
|
||||
&actSetBalance{cfg, nil, &utils.APAction{Type: utils.MetaSetBalance}, "cgrates.org", true},
|
||||
&actRemBalance{cfg, nil, &utils.APAction{Type: utils.MetaRemBalance}, "cgrates.org"},
|
||||
&actSetBalance{cfg, nil, fltr, &utils.APAction{Type: utils.MetaAddBalance}, "cgrates.org", false},
|
||||
&actSetBalance{cfg, nil, fltr, &utils.APAction{Type: utils.MetaSetBalance}, "cgrates.org", true},
|
||||
&actRemBalance{cfg, nil, fltr, &utils.APAction{Type: utils.MetaRemBalance}, "cgrates.org"},
|
||||
}
|
||||
|
||||
acts, err := newActionersFromActions(context.Background(), new(utils.CGREvent), cfg, fltr, dm, nil, actCfg, "cgrates.org")
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -72,11 +72,17 @@ func TestDynThdIT(t *testing.T) {
|
||||
Type: utils.MetaSetBalance,
|
||||
Diktats: []*utils.APDiktat{
|
||||
{
|
||||
ID: "SetVoiceID",
|
||||
ID: "SetVoiceID",
|
||||
FilterIDs: []string{"*string:~*req.Account:1002"},
|
||||
Opts: map[string]any{
|
||||
"*balancePath": "*balance.VOICE.ID",
|
||||
"*balanceValue": "testBalanceIDMonetary",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 14,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetMonetaryType",
|
||||
@@ -84,6 +90,11 @@ func TestDynThdIT(t *testing.T) {
|
||||
"*balancePath": "*balance.MONETARY.Type",
|
||||
"*balanceValue": utils.MetaConcrete,
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 13,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetMonetaryUnits",
|
||||
@@ -91,6 +102,11 @@ func TestDynThdIT(t *testing.T) {
|
||||
"*balancePath": "*balance.MONETARY.Units",
|
||||
"*balanceValue": "1048576",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 12,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetMonetaryWeights",
|
||||
@@ -98,6 +114,11 @@ func TestDynThdIT(t *testing.T) {
|
||||
"*balancePath": "*balance.MONETARY.Weights",
|
||||
"*balanceValue": "`;2`",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 11,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetMonetaryCostIncrements",
|
||||
@@ -105,6 +126,41 @@ func TestDynThdIT(t *testing.T) {
|
||||
"*balancePath": "*balance.MONETARY.CostIncrements",
|
||||
"*balanceValue": "`*string:~*req.ToR:*data;1024;0;0.01`",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 9,
|
||||
},
|
||||
},
|
||||
Blockers: utils.DynamicBlockers{
|
||||
{
|
||||
Blocker: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetVoiceIDNotFoundFilter",
|
||||
FilterIDs: []string{"*string:~*req.Account:1003"},
|
||||
Opts: map[string]any{
|
||||
"*balancePath": "*balance.VOICE.ID",
|
||||
"*balanceValue": "testBalanceIDMonetaryNOTFOUND",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "SetVoiceIDBlocked",
|
||||
Opts: map[string]any{
|
||||
"*balancePath": "*balance.VOICE.ID",
|
||||
"*balanceValue": "testBalanceIDMonetaryBLOCKED",
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user