func TestSearchExtraField(t *testing.T) { fsCdr, _ := NewFSCdr(body, fsCdrCfg) rsrSt1, _ := utils.NewRSRField("^injected_value") rsrSt2, _ := utils.NewRSRField("^injected_hdr::injected_value/") fsCdrCfg.CDRSExtraFields = []*utils.RSRField{&utils.RSRField{Id: "caller_id_name"}, rsrSt1, rsrSt2} extraFields := fsCdr.getExtraFields() if len(extraFields) != 3 || extraFields["caller_id_name"] != "1001" || extraFields["injected_value"] != "injected_value" || extraFields["injected_hdr"] != "injected_value" { t.Error("Error parsing extra fields: ", extraFields) } }
func TestPassesFieldFilterDn1(t *testing.T) { cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem0005", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } acntPrefxFltr, _ := utils.NewRSRField(`~Account:s/^\w+[shmp]\d{4}$//`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem00005", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0402129281", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^0\d{9}$//`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^0(\d{9})$/placeholder/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "04021292812", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0162447222", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if acntPrefxFltr, err := utils.NewRSRField(`~Account:s/^0\d{9}$//`); err != nil { t.Error("Unexpected parse error", err) } else if acntPrefxFltr == nil { t.Error("Failed parsing rule") } else if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } if acntPrefxFltr, err := utils.NewRSRField(`~Account:s/^\w+[shmp]\d{4}$//`); err != nil { t.Error("Unexpected parse error", err) } else if acntPrefxFltr == nil { t.Error("Failed parsing rule") } else if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } }
func TestPassesFieldFilterDn1(t *testing.T) { body := `Event-Name: RE_SCHEDULE Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: futurem0005` ev := new(FSEvent).AsEvent(body) acntPrefxFltr, _ := utils.NewRSRField(`~Account:s/^\w+[shmp]\d{4}$//`) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } body = `Event-Name: RE_SCHEDULE Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: futurem00005` ev = new(FSEvent).AsEvent(body) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } body = `Event-Name: RE_SCHEDULE Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: 0402129281` ev = new(FSEvent).AsEvent(body) acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^0\d{9}$//`) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^0(\d{9})$/placeholder/`) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } body = `Event-Name: RE_SCHEDULE Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: 04021292812` ev = new(FSEvent).AsEvent(body) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } }
func TestCdreCdrFieldValue(t *testing.T) { cdre := new(CdrExporter) cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01} fltrRule, _ := utils.NewRSRField("~tenant:s/(.+)/cgrates.org/") if val, err := cdre.cdrFieldValue(cdr, fltrRule, &utils.RSRField{Id: "destination"}, ""); err != nil { t.Error(err) } else if val != cdr.Destination { t.Errorf("Expecting: %s, received: %s", cdr.Destination, val) } fltrRule, _ = utils.NewRSRField("~tenant:s/(.+)/itsyscom.com/") if _, err := cdre.cdrFieldValue(cdr, fltrRule, &utils.RSRField{Id: "destination"}, ""); err == nil { t.Error("Failed to use filter") } }
func TestCdreGetCombimedCdrFieldVal(t *testing.T) { logDb, _ := engine.NewMapStorage() cfg, _ := config.NewDefaultCGRConfig() cdrs := []*utils.StoredCdr{ &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: "RUN_RTL", Cost: 1.01}, &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf2", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: "CUSTOMER1", Cost: 2.01}, &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: "CUSTOMER1", Cost: 3.01}, &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 4.01}, &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1000", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: "RETAIL1", Cost: 5.01}, } cdre, err := NewCdrExporter(cdrs, logDb, cfg.CdreDefaultInstance, cfg.CdreDefaultInstance.CdrFormat, cfg.CdreDefaultInstance.FieldSeparator, "firstexport", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify) if err != nil { t.Error("Unexpected error received: ", err) } fltrRule, _ := utils.NewRSRField("~mediation_runid:s/default/RUN_RTL/") if costVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], fltrRule, &utils.RSRField{Id: "cost"}); err != nil { t.Error(err) } else if costVal != "1.01" { t.Error("Expecting: 1.01, received: ", costVal) } fltrRule, _ = utils.NewRSRField("~mediation_runid:s/default/RETAIL1/") if acntVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], fltrRule, &utils.RSRField{Id: "account"}); err != nil { t.Error(err) } else if acntVal != "1000" { t.Error("Expecting: 1000, received: ", acntVal) } }
func (self *CmdParse) LocalExecute() string { if self.rpcParams.Expression == "" { return "Empty expression error" } if self.rpcParams.Value == "" { return "Empty value error" } if rsrField, err := utils.NewRSRField(self.rpcParams.Expression); err == nil { return rsrField.ParseValue(self.rpcParams.Value) } else { return err.Error() } }
// Converts a list of field identifiers into proper CDR field content func NewCdreCdrFieldsFromIds(withFixedWith bool, fldsIds ...string) ([]*CdreCdrField, error) { cdrFields := make([]*CdreCdrField, len(fldsIds)) for idx, fldId := range fldsIds { if parsedRsr, err := utils.NewRSRField(fldId); err != nil { return nil, err } else { cdrFld := &CdreCdrField{Name: fldId, Type: utils.CDRFIELD, Value: fldId, valueAsRsrField: parsedRsr} if err := cdrFld.setDefaultFieldProperties(withFixedWith); err != nil { // Set default fixed width properties to be used later if needed return nil, err } cdrFields[idx] = cdrFld } } return cdrFields, nil }
func TestPassesFieldFilter(t *testing.T) { 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_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", 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), MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } if pass, _ := cdr.PassesFieldFilter(nil); !pass { t.Error("Not passing filter") } acntPrefxFltr, _ := utils.NewRSRField(`~Account:s/(.+)/1001/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing filter") } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^(10)\d\d$/10/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^\d(10)\d$/10/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Passing filter") } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^(10)\d\d$/010/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Passing filter") } acntPrefxFltr, _ = utils.NewRSRField(`~Account:s/^1010$/1010/`) if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Passing filter") } torFltr, _ := utils.NewRSRField(`^TOR::*voice/`) if pass, _ := cdr.PassesFieldFilter(torFltr); !pass { t.Error("Not passing filter") } torFltr, _ = utils.NewRSRField(`^TOR/*data/`) if pass, _ := cdr.PassesFieldFilter(torFltr); pass { t.Error("Passing filter") } inexistentFieldFltr, _ := utils.NewRSRField(`^fakefield/fakevalue/`) if pass, _ := cdr.PassesFieldFilter(inexistentFieldFltr); pass { t.Error("Passing filter") } }
func TestXmlCdreCfgPopulateCdreRSRFIeld(t *testing.T) { cdreField := CgrXmlCfgCdrField{Name: "TEST1", Type: "cdrfield", Value: `~effective_caller_id_number:s/(\d+)/+$1/`} if err := cdreField.populateRSRField(); err != nil { t.Error("Unexpected error: ", err.Error()) } else if cdreField.valueAsRsrField == nil { t.Error("Failed loading the RSRField") } valRSRField, _ := utils.NewRSRField(`~effective_caller_id_number:s/(\d+)/+$1/`) if recv := cdreField.ValueAsRSRField(); !reflect.DeepEqual(valRSRField, recv) { t.Errorf("Expecting %v, received %v", valRSRField, recv) } /*cdreField = CgrXmlCfgCdrField{Name: "TEST1", Type: "constant", Value: `someval`} if err := cdreField.populateRSRField(); err != nil { t.Error("Unexpected error: ", err.Error()) } else if cdreField.valueAsRsrField != nil { t.Error("Should not load the RSRField") }*/ }
func TestCdreExtraFields(t *testing.T) { eFieldsCfg := []byte(`[cdre] cdr_format = csv export_template = cgrid,mediation_runid,accid `) expectedFlds := []*CdreCdrField{ &CdreCdrField{Name: "cgrid", Type: utils.CDRFIELD, Value: "cgrid", valueAsRsrField: &utils.RSRField{Id: "cgrid"}, Mandatory: true}, &CdreCdrField{Name: "mediation_runid", Type: utils.CDRFIELD, Value: "mediation_runid", valueAsRsrField: &utils.RSRField{Id: "mediation_runid"}, Mandatory: true}, &CdreCdrField{Name: "accid", Type: utils.CDRFIELD, Value: "accid", valueAsRsrField: &utils.RSRField{Id: "accid"}, Mandatory: true}, } expCdreCfg := &CdreConfig{CdrFormat: utils.CSV, FieldSeparator: utils.CSV_SEP, CostRoundingDecimals: -1, ExportDir: "/var/log/cgrates/cdre", ContentFields: expectedFlds} if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil { t.Error("Could not parse the config", err.Error()) } else if !reflect.DeepEqual(cfg.CdreDefaultInstance, expCdreCfg) { t.Errorf("Expecting: %v, received: %v", expCdreCfg, cfg.CdreDefaultInstance) } eFieldsCfg = []byte(`[cdre] cdr_format = csv export_template = cgrid,~effective_caller_id_number:s/(\d+)/+$1/ `) rsrField, _ := utils.NewRSRField(`~effective_caller_id_number:s/(\d+)/+$1/`) expectedFlds = []*CdreCdrField{ &CdreCdrField{Name: "cgrid", Type: utils.CDRFIELD, Value: "cgrid", valueAsRsrField: &utils.RSRField{Id: "cgrid"}, Mandatory: true}, &CdreCdrField{Name: `~effective_caller_id_number:s/(\d+)/+$1/`, Type: utils.CDRFIELD, Value: `~effective_caller_id_number:s/(\d+)/+$1/`, valueAsRsrField: rsrField, Mandatory: false}} expCdreCfg.ContentFields = expectedFlds if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil { t.Error("Could not parse the config", err.Error()) } else if !reflect.DeepEqual(cfg.CdreDefaultInstance, expCdreCfg) { t.Errorf("Expecting: %v, received: %v", expCdreCfg, cfg.CdreDefaultInstance) } eFieldsCfg = []byte(`[cdre] cdr_format = csv export_template = cgrid,~accid:s/(\d)/$1,runid `) if _, err := NewCGRConfigFromBytes(eFieldsCfg); err == nil { t.Error("Failed to detect failed RSRParsing") } }
func TestGetDateTimeFieldVal(t *testing.T) { cdreTst := new(CdrExporter) cdrTst := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01, ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}} if cdrVal, err := cdreTst.getDateTimeFieldVal(cdrTst, nil, &utils.RSRField{Id: "stop_time"}, "2006-01-02 15:04:05"); err != nil { t.Error(err) } else if cdrVal != "2014-06-11 19:19:00" { t.Error("Expecting: 2014-06-11 19:19:00, got: ", cdrVal) } // Test filter fltrRule, _ := utils.NewRSRField("~tenant:s/(.+)/itsyscom.com/") if _, err := cdreTst.getDateTimeFieldVal(cdrTst, fltrRule, &utils.RSRField{Id: "stop_time"}, "2006-01-02 15:04:05"); err == nil { t.Error(err) } // Test time parse error if _, err := cdreTst.getDateTimeFieldVal(cdrTst, nil, &utils.RSRField{Id: "fieldextr2"}, "2006-01-02 15:04:05"); err == nil { t.Error("Should give error here, got none.") } }
func TestStoredCdrForkCdrStaticVals(t *testing.T) { storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, } rsrStPostpaid, _ := utils.NewRSRField("^" + utils.META_POSTPAID) rsrStIn, _ := utils.NewRSRField("^*in") rsrStCgr, _ := utils.NewRSRField("^cgrates.com") rsrStPC, _ := utils.NewRSRField("^premium_call") rsrStFA, _ := utils.NewRSRField("^first_account") rsrStFS, _ := utils.NewRSRField("^first_subject") rsrStST, _ := utils.NewRSRField("^2013-12-07T08:42:24Z") rsrStAT, _ := utils.NewRSRField("^2013-12-07T08:42:26Z") rsrStDur, _ := utils.NewRSRField("^12s") rsrStSuppl, _ := utils.NewRSRField("^supplier1") rsrStDCause, _ := utils.NewRSRField("^HANGUP_COMPLETE") rsrPdd, _ := utils.NewRSRField("^3") rsrStRated, _ := utils.NewRSRField("^true") rsrStCost, _ := utils.NewRSRField("^1.2") rtCdrOut2, err := storCdr.ForkCdr("wholesale_run", rsrStPostpaid, rsrStIn, rsrStCgr, rsrStPC, rsrStFA, rsrStFS, &utils.RSRField{Id: utils.DESTINATION}, rsrStST, rsrPdd, rsrStAT, rsrStDur, rsrStSuppl, rsrStDCause, rsrStRated, rsrStCost, []*utils.RSRField{}, true, "") if err != nil { t.Error("Unexpected error received", err) } expctRatedCdr2 := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID, Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(12) * time.Second, Pdd: time.Duration(3) * time.Second, Supplier: "supplier1", DisconnectCause: "HANGUP_COMPLETE", Rated: true, Cost: 1.2, ExtraFields: map[string]string{}, MediationRunId: "wholesale_run"} if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) { t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2) } _, err = storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: "dummy_header"}, &utils.RSRField{Id: utils.DIRECTION}, &utils.RSRField{Id: utils.TENANT}, &utils.RSRField{Id: utils.TOR}, &utils.RSRField{Id: utils.ACCOUNT}, &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION}, &utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.PDD}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE}, &utils.RSRField{Id: utils.SUPPLIER}, &utils.RSRField{Id: utils.DISCONNECT_CAUSE}, &utils.RSRField{Id: utils.RATED_FLD}, &utils.RSRField{Id: utils.COST}, []*utils.RSRField{}, true, "") if err == nil { t.Error("Failed to detect missing header") } }
func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) error { storedCdr.MediationRunId = utils.DEFAULT_RUNID cdrRuns := []*utils.StoredCdr{storedCdr} // Start with initial storCdr, will add here all to be mediated attrsDC := utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction, Account: storedCdr.Account, Subject: storedCdr.Subject} var dcs utils.DerivedChargers if err := self.connector.GetDerivedChargers(attrsDC, &dcs); err != nil { errText := fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error()) Logger.Err(errText) return errors.New(errText) } for _, dc := range dcs { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := storedCdr.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcATimeFld, dcDurFld, []*utils.RSRField{}, true) if err != nil { // Errors on fork, cannot calculate further, write that into db for later analysis self.cdrDb.SetRatedCdr(&utils.StoredCdr{CgrId: storedCdr.CgrId, CdrSource: utils.FORKED_CDR, MediationRunId: dc.RunId, Cost: -1}, err.Error()) // Cannot fork CDR, important just runid and error continue } cdrRuns = append(cdrRuns, forkedCdr) } for _, cdr := range cdrRuns { extraInfo := "" if err := self.rateCDR(cdr); err != nil { extraInfo = err.Error() } if !self.cgrCfg.MediatorStoreDisable { if err := self.cdrDb.SetRatedCdr(cdr, extraInfo); err != nil { Logger.Err(fmt.Sprintf("<Mediator> Could not record cost for cgrid: <%s>, ERROR: <%s>, cost: %f, extraInfo: %s", cdr.CgrId, err.Error(), cdr.Cost, extraInfo)) } } if sendToStats && self.stats != nil { // We send to stats only after saving to db since there are chances we cannot store and then no way to reproduce stats offline go func(cdr *utils.StoredCdr) { // Pass it by value since the variable will be overwritten by for if err := self.stats.AppendCDR(cdr, nil); err != nil { Logger.Err(fmt.Sprintf("Could not append cdr to stats (mediator): %s", err.Error())) } }(cdr) } } return nil }
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, pddFld, answerTimeFld, durationFld, supplierFld, disconnectCauseFld *utils.RSRField, extraFlds []*utils.RSRField, primaryMandatory bool, timezone string) (*StoredCdr, error) { if reqTypeFld == nil { reqTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if reqTypeFld.Id == utils.META_DEFAULT { reqTypeFld.Id = utils.REQTYPE } if directionFld == nil { directionFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if directionFld.Id == utils.META_DEFAULT { directionFld.Id = utils.DIRECTION } if tenantFld == nil { tenantFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if tenantFld.Id == utils.META_DEFAULT { tenantFld.Id = utils.TENANT } if categFld == nil { categFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if categFld.Id == utils.META_DEFAULT { categFld.Id = utils.CATEGORY } if accountFld == nil { accountFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if accountFld.Id == utils.META_DEFAULT { accountFld.Id = utils.ACCOUNT } if subjectFld == nil { subjectFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if subjectFld.Id == utils.META_DEFAULT { subjectFld.Id = utils.SUBJECT } if destFld == nil { destFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if destFld.Id == utils.META_DEFAULT { destFld.Id = utils.DESTINATION } if setupTimeFld == nil { setupTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if setupTimeFld.Id == utils.META_DEFAULT { setupTimeFld.Id = utils.SETUP_TIME } if answerTimeFld == nil { answerTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if answerTimeFld.Id == utils.META_DEFAULT { answerTimeFld.Id = utils.ANSWER_TIME } if durationFld == nil { durationFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if durationFld.Id == utils.META_DEFAULT { durationFld.Id = utils.USAGE } if pddFld == nil { pddFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if pddFld.Id == utils.META_DEFAULT { pddFld.Id = utils.PDD } if supplierFld == nil { supplierFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if supplierFld.Id == utils.META_DEFAULT { supplierFld.Id = utils.SUPPLIER } if disconnectCauseFld == nil { disconnectCauseFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if disconnectCauseFld.Id == utils.META_DEFAULT { disconnectCauseFld.Id = utils.DISCONNECT_CAUSE } var err error frkStorCdr := new(StoredCdr) frkStorCdr.CgrId = storedCdr.CgrId frkStorCdr.TOR = storedCdr.TOR frkStorCdr.MediationRunId = runId frkStorCdr.Cost = -1.0 // Default for non-rated CDR frkStorCdr.AccId = storedCdr.AccId frkStorCdr.CdrHost = storedCdr.CdrHost frkStorCdr.CdrSource = storedCdr.CdrSource frkStorCdr.ReqType = storedCdr.FieldAsString(reqTypeFld) if primaryMandatory && len(frkStorCdr.ReqType) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.REQTYPE, reqTypeFld.Id) } frkStorCdr.Direction = storedCdr.FieldAsString(directionFld) if primaryMandatory && len(frkStorCdr.Direction) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.DIRECTION, directionFld.Id) } frkStorCdr.Tenant = storedCdr.FieldAsString(tenantFld) if primaryMandatory && len(frkStorCdr.Tenant) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.TENANT, tenantFld.Id) } frkStorCdr.Category = storedCdr.FieldAsString(categFld) if primaryMandatory && len(frkStorCdr.Category) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.CATEGORY, categFld.Id) } frkStorCdr.Account = storedCdr.FieldAsString(accountFld) if primaryMandatory && len(frkStorCdr.Account) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ACCOUNT, accountFld.Id) } frkStorCdr.Subject = storedCdr.FieldAsString(subjectFld) if primaryMandatory && len(frkStorCdr.Subject) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SUBJECT, subjectFld.Id) } frkStorCdr.Destination = storedCdr.FieldAsString(destFld) if primaryMandatory && len(frkStorCdr.Destination) == 0 && frkStorCdr.TOR == utils.VOICE { return nil, utils.NewErrMandatoryIeMissing(utils.DESTINATION, destFld.Id) } sTimeStr := storedCdr.FieldAsString(setupTimeFld) if primaryMandatory && len(sTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SETUP_TIME, setupTimeFld.Id) } else if frkStorCdr.SetupTime, err = utils.ParseTimeDetectLayout(sTimeStr, timezone); err != nil { return nil, err } aTimeStr := storedCdr.FieldAsString(answerTimeFld) if primaryMandatory && len(aTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ANSWER_TIME, answerTimeFld.Id) } else if frkStorCdr.AnswerTime, err = utils.ParseTimeDetectLayout(aTimeStr, timezone); err != nil { return nil, err } durStr := storedCdr.FieldAsString(durationFld) if primaryMandatory && len(durStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.USAGE, durationFld.Id) } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { return nil, err } pddStr := storedCdr.FieldAsString(pddFld) if primaryMandatory && len(pddStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.PDD, pddFld.Id) } else if frkStorCdr.Pdd, err = utils.ParseDurationWithSecs(pddStr); err != nil { return nil, err } frkStorCdr.Supplier = storedCdr.FieldAsString(supplierFld) frkStorCdr.DisconnectCause = storedCdr.FieldAsString(disconnectCauseFld) frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds)) for _, fld := range extraFlds { frkStorCdr.ExtraFields[fld.Id] = storedCdr.FieldAsString(fld) } return frkStorCdr, nil }
func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { dfltCDRRun := cdr.Clone() cdrRuns := []*CDR{dfltCDRRun} if cdr.RunID != utils.MetaRaw { // Only derive *raw CDRs return cdrRuns, nil } dfltCDRRun.RunID = utils.META_DEFAULT // Rewrite *raw with *default since we have it as first run if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { return nil, err } if err := LoadAlias(&AttrMatchingAlias{ Destination: cdr.Destination, Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, Subject: cdr.Subject, Context: utils.ALIAS_CONTEXT_RATING, }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return nil, err } attrsDC := &utils.AttrDerivedChargers{Tenant: cdr.Tenant, Category: cdr.Category, Direction: cdr.Direction, Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination} var dcs utils.DerivedChargers if err := self.rals.Call("Responder.GetDerivedChargers", attrsDC, &dcs); err != nil { utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", cdr.CGRID, err.Error())) return nil, err } for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if !dcRunFilter.FilterPasses(cdr.FieldAsString(dcRunFilter)) { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcRequestTypeFld, _ := utils.NewRSRField(dc.RequestTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcPddFld, _ := utils.NewRSRField(dc.PDDField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) dcSupplFld, _ := utils.NewRSRField(dc.SupplierField) dcDCauseFld, _ := utils.NewRSRField(dc.DisconnectCauseField) dcRatedFld, _ := utils.NewRSRField(dc.RatedField) dcCostFld, _ := utils.NewRSRField(dc.CostField) forkedCdr, err := cdr.ForkCdr(dc.RunID, dcRequestTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, []*utils.RSRField{}, true, self.cgrCfg.DefaultTimezone) if err != nil { utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", cdr.CGRID, dc.RunID, err.Error())) continue // do not add it to the forked CDR list } if !forkedCdr.Rated { forkedCdr.Cost = -1.0 // Make sure that un-rated CDRs start with Cost -1 } cdrRuns = append(cdrRuns, forkedCdr) } return cdrRuns, nil }
func TestXmlCdreCfgAsCdreConfig(t *testing.T) { cfgXmlStr := `<?xml version="1.0" encoding="UTF-8"?> <document type="cgrates/xml"> <configuration section="cdre" type="fixed_width" id="CDRE-FW2"> <cdr_format>fwv</cdr_format> <field_separator>;</field_separator> <data_usage_multiply_factor>1024.0</data_usage_multiply_factor> <cost_multiply_factor>1.19</cost_multiply_factor> <cost_rounding_decimals>-1</cost_rounding_decimals> <cost_shift_digits>-3</cost_shift_digits> <mask_destination_id>MASKED_DESTINATIONS</mask_destination_id> <mask_length>1</mask_length> <export_dir>/var/log/cgrates/cdre</export_dir> <export_template> <header> <fields> <field name="TypeOfRecord" type="constant" value="10" width="2" /> <field name="LastCdr" type="metatag" value="last_cdr_time" layout="020106150400" width="12" /> </fields> </header> <content> <fields> <field name="OperatorCode" type="cdrfield" value="operator" width="2" /> <field name="ProductId" type="cdrfield" value="productid" width="5" /> <field name="NetworkId" type="constant" value="3" width="1" /> <field name="FromHttpPost1" type="http_post" value="https://localhost:8000" width="10" strip="xright" padding="left" /> <field name="CombiMed1" type="combimed" value="cost" width="10" strip="xright" padding="left" filter="~mediation_runid:s/DEFAULT/SECOND_RUN/"/> </fields> </content> <trailer> <fields> <field name="DistributorCode" type="constant" value="VOI" width="3" /> <field name="FileSeqNr" type="metatag" value="export_id" padding="zeroleft" width="5" /> </fields> </trailer> </export_template> </configuration> </document>` var err error reader := strings.NewReader(cfgXmlStr) if cfgDoc, err = ParseCgrXmlConfig(reader); err != nil { t.Error(err.Error()) } else if cfgDoc == nil { t.Fatal("Could not parse xml configuration document") } xmlCdreCfgs := cfgDoc.GetCdreCfgs("CDRE-FW2") if xmlCdreCfgs == nil { t.Error("Could not parse XmlCdre instance") } eCdreCfg := &CdreConfig{ CdrFormat: "fwv", FieldSeparator: ';', DataUsageMultiplyFactor: 1024.0, CostMultiplyFactor: 1.19, CostRoundingDecimals: -1, CostShiftDigits: -3, MaskDestId: "MASKED_DESTINATIONS", MaskLength: 1, ExportDir: "/var/log/cgrates/cdre", } fltrCombiMed, _ := utils.NewRSRField("~mediation_runid:s/DEFAULT/SECOND_RUN/") eCdreCfg.HeaderFields = []*CdreCdrField{ &CdreCdrField{ Name: "TypeOfRecord", Type: "constant", Value: "10", Width: 2, valueAsRsrField: &utils.RSRField{Id: "10"}}, &CdreCdrField{ Name: "LastCdr", Type: "metatag", Value: "last_cdr_time", Layout: "020106150400", Width: 12, valueAsRsrField: &utils.RSRField{Id: "last_cdr_time"}}, } eCdreCfg.ContentFields = []*CdreCdrField{ &CdreCdrField{ Name: "OperatorCode", Type: "cdrfield", Value: "operator", Width: 2, valueAsRsrField: &utils.RSRField{Id: "operator"}, }, &CdreCdrField{ Name: "ProductId", Type: "cdrfield", Value: "productid", Width: 5, valueAsRsrField: &utils.RSRField{Id: "productid"}, }, &CdreCdrField{ Name: "NetworkId", Type: "constant", Value: "3", Width: 1, valueAsRsrField: &utils.RSRField{Id: "3"}, }, &CdreCdrField{ Name: "FromHttpPost1", Type: "http_post", Value: "https://localhost:8000", Width: 10, Strip: "xright", Padding: "left", valueAsRsrField: &utils.RSRField{Id: "https://localhost:8000"}, }, &CdreCdrField{ Name: "CombiMed1", Type: "combimed", Value: "cost", Width: 10, Strip: "xright", Padding: "left", Filter: fltrCombiMed, valueAsRsrField: &utils.RSRField{Id: "cost"}, }, } eCdreCfg.TrailerFields = []*CdreCdrField{ &CdreCdrField{ Name: "DistributorCode", Type: "constant", Value: "VOI", Width: 3, valueAsRsrField: &utils.RSRField{Id: "VOI"}, }, &CdreCdrField{ Name: "FileSeqNr", Type: "metatag", Value: "export_id", Width: 5, Padding: "zeroleft", valueAsRsrField: &utils.RSRField{Id: "export_id"}, }, } if rcvCdreCfg := xmlCdreCfgs["CDRE-FW2"].AsCdreConfig(); !reflect.DeepEqual(rcvCdreCfg, eCdreCfg) { for _, fld := range rcvCdreCfg.ContentFields { fmt.Printf("Fld: %+v\n", fld) } t.Errorf("Expecting: %v, received: %v", eCdreCfg, rcvCdreCfg) } }
func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { if len(storedCdr.MediationRunId) == 0 { storedCdr.MediationRunId = utils.META_DEFAULT } cdrRuns := []*StoredCdr{storedCdr} if storedCdr.Rated { // Do not derive already rated CDRs since they should be already derived return cdrRuns, nil } attrsDC := &utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction, Account: storedCdr.Account, Subject: storedCdr.Subject, Destination: storedCdr.Destination} var dcs utils.DerivedChargers if err := self.rater.GetDerivedChargers(attrsDC, &dcs); err != nil { utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error())) return nil, err } for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := storedCdr.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcPddFld, _ := utils.NewRSRField(dc.PddField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) dcSupplFld, _ := utils.NewRSRField(dc.SupplierField) dcDCauseFld, _ := utils.NewRSRField(dc.DisconnectCauseField) dcRatedFld, _ := utils.NewRSRField(dc.RatedField) dcCostFld, _ := utils.NewRSRField(dc.CostField) forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, []*utils.RSRField{}, true, self.cgrCfg.DefaultTimezone) if err != nil { utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", storedCdr.CgrId, dc.RunId, err.Error())) continue // do not add it to the forked CDR list } if !forkedCdr.Rated { forkedCdr.Cost = -1.0 // Make sure that un-rated CDRs start with Cost -1 } cdrRuns = append(cdrRuns, forkedCdr) } return cdrRuns, nil }
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored func (cdr *CDR) ForkCdr(runId string, RequestTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, PDDFld, answerTimeFld, durationFld, supplierFld, disconnectCauseFld, ratedFld, costFld *utils.RSRField, extraFlds []*utils.RSRField, primaryMandatory bool, timezone string) (*CDR, error) { if RequestTypeFld == nil { RequestTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if RequestTypeFld.Id == utils.META_DEFAULT { RequestTypeFld.Id = utils.REQTYPE } if directionFld == nil { directionFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if directionFld.Id == utils.META_DEFAULT { directionFld.Id = utils.DIRECTION } if tenantFld == nil { tenantFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if tenantFld.Id == utils.META_DEFAULT { tenantFld.Id = utils.TENANT } if categFld == nil { categFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if categFld.Id == utils.META_DEFAULT { categFld.Id = utils.CATEGORY } if accountFld == nil { accountFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if accountFld.Id == utils.META_DEFAULT { accountFld.Id = utils.ACCOUNT } if subjectFld == nil { subjectFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if subjectFld.Id == utils.META_DEFAULT { subjectFld.Id = utils.SUBJECT } if destFld == nil { destFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if destFld.Id == utils.META_DEFAULT { destFld.Id = utils.DESTINATION } if setupTimeFld == nil { setupTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if setupTimeFld.Id == utils.META_DEFAULT { setupTimeFld.Id = utils.SETUP_TIME } if answerTimeFld == nil { answerTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if answerTimeFld.Id == utils.META_DEFAULT { answerTimeFld.Id = utils.ANSWER_TIME } if durationFld == nil { durationFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if durationFld.Id == utils.META_DEFAULT { durationFld.Id = utils.USAGE } if PDDFld == nil { PDDFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if PDDFld.Id == utils.META_DEFAULT { PDDFld.Id = utils.PDD } if supplierFld == nil { supplierFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if supplierFld.Id == utils.META_DEFAULT { supplierFld.Id = utils.SUPPLIER } if disconnectCauseFld == nil { disconnectCauseFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if disconnectCauseFld.Id == utils.META_DEFAULT { disconnectCauseFld.Id = utils.DISCONNECT_CAUSE } if ratedFld == nil { ratedFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if ratedFld.Id == utils.META_DEFAULT { ratedFld.Id = utils.RATED_FLD } if costFld == nil { costFld, _ = utils.NewRSRField(utils.META_DEFAULT) } if costFld.Id == utils.META_DEFAULT { costFld.Id = utils.COST } var err error frkStorCdr := new(CDR) frkStorCdr.CGRID = cdr.CGRID frkStorCdr.ToR = cdr.ToR frkStorCdr.RunID = runId frkStorCdr.Cost = -1.0 // Default for non-rated CDR frkStorCdr.OriginID = cdr.OriginID frkStorCdr.OriginHost = cdr.OriginHost frkStorCdr.Source = cdr.Source frkStorCdr.RequestType = cdr.FieldAsString(RequestTypeFld) if primaryMandatory && len(frkStorCdr.RequestType) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.REQTYPE, RequestTypeFld.Id) } frkStorCdr.Direction = cdr.FieldAsString(directionFld) if primaryMandatory && len(frkStorCdr.Direction) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.DIRECTION, directionFld.Id) } frkStorCdr.Tenant = cdr.FieldAsString(tenantFld) if primaryMandatory && len(frkStorCdr.Tenant) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.TENANT, tenantFld.Id) } frkStorCdr.Category = cdr.FieldAsString(categFld) if primaryMandatory && len(frkStorCdr.Category) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.CATEGORY, categFld.Id) } frkStorCdr.Account = cdr.FieldAsString(accountFld) if primaryMandatory && len(frkStorCdr.Account) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ACCOUNT, accountFld.Id) } frkStorCdr.Subject = cdr.FieldAsString(subjectFld) if primaryMandatory && len(frkStorCdr.Subject) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SUBJECT, subjectFld.Id) } frkStorCdr.Destination = cdr.FieldAsString(destFld) if primaryMandatory && len(frkStorCdr.Destination) == 0 && frkStorCdr.ToR == utils.VOICE { return nil, utils.NewErrMandatoryIeMissing(utils.DESTINATION, destFld.Id) } sTimeStr := cdr.FieldAsString(setupTimeFld) if primaryMandatory && len(sTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.SETUP_TIME, setupTimeFld.Id) } else if frkStorCdr.SetupTime, err = utils.ParseTimeDetectLayout(sTimeStr, timezone); err != nil { return nil, err } aTimeStr := cdr.FieldAsString(answerTimeFld) if primaryMandatory && len(aTimeStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.ANSWER_TIME, answerTimeFld.Id) } else if frkStorCdr.AnswerTime, err = utils.ParseTimeDetectLayout(aTimeStr, timezone); err != nil { return nil, err } durStr := cdr.FieldAsString(durationFld) if primaryMandatory && len(durStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.USAGE, durationFld.Id) } else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil { return nil, err } PDDStr := cdr.FieldAsString(PDDFld) if primaryMandatory && len(PDDStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.PDD, PDDFld.Id) } else if frkStorCdr.PDD, err = utils.ParseDurationWithSecs(PDDStr); err != nil { return nil, err } frkStorCdr.Supplier = cdr.FieldAsString(supplierFld) frkStorCdr.DisconnectCause = cdr.FieldAsString(disconnectCauseFld) ratedStr := cdr.FieldAsString(ratedFld) if primaryMandatory && len(ratedStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.RATED_FLD, ratedFld.Id) } else if frkStorCdr.Rated, err = strconv.ParseBool(ratedStr); err != nil { return nil, err } costStr := cdr.FieldAsString(costFld) if primaryMandatory && len(costStr) == 0 { return nil, utils.NewErrMandatoryIeMissing(utils.COST, costFld.Id) } else if frkStorCdr.Cost, err = strconv.ParseFloat(costStr, 64); err != nil { return nil, err } frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds)) for _, fld := range extraFlds { frkStorCdr.ExtraFields[fld.Id] = cdr.FieldAsString(fld) } return frkStorCdr, nil }