mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-23 08:08:45 +05:00
AccountSummary inside CDR object, decoupling it from CallCost for error cases
This commit is contained in:
@@ -28,6 +28,7 @@ CREATE TABLE cdrs (
|
||||
cost_source varchar(64) NOT NULL,
|
||||
cost DECIMAL(20,4) NOT NULL,
|
||||
cost_details text,
|
||||
account_summary text,
|
||||
extra_info text,
|
||||
created_at TIMESTAMP NULL,
|
||||
updated_at TIMESTAMP NULL,
|
||||
|
||||
@@ -28,6 +28,7 @@ CREATE TABLE cdrs (
|
||||
cost_source VARCHAR(64) NOT NULL,
|
||||
cost NUMERIC(20,4) DEFAULT NULL,
|
||||
cost_details jsonb,
|
||||
account_summary jsonb,
|
||||
extra_info text,
|
||||
created_at TIMESTAMP,
|
||||
updated_at TIMESTAMP NULL,
|
||||
|
||||
@@ -1036,6 +1036,13 @@ func (acc *Account) AsAccountSummary() *AccountSummary {
|
||||
return ad
|
||||
}
|
||||
|
||||
func NewAccountSummaryFromJSON(jsn string) (acntSummary *AccountSummary, err error) {
|
||||
if !utils.IsSliceMember([]string{"", "null"}, jsn) { // Unmarshal only when content
|
||||
json.Unmarshal([]byte(jsn), &acntSummary)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AccountDigest contains compressed information about an Account
|
||||
type AccountSummary struct {
|
||||
Tenant string
|
||||
|
||||
@@ -1873,6 +1873,14 @@ func TestAccountGetBalancesForPrefixMixedBad(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountNewAccountSummaryFromJSON(t *testing.T) {
|
||||
if acnt, err := NewAccountSummaryFromJSON("null"); err != nil {
|
||||
t.Error(err)
|
||||
} else if acnt != nil {
|
||||
t.Errorf("Expecting nil, received: %+v", acnt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountAsAccountDigest(t *testing.T) {
|
||||
acnt1 := &Account{
|
||||
ID: "cgrates.org:account1",
|
||||
|
||||
@@ -30,7 +30,6 @@ type CallCost struct {
|
||||
Cost float64
|
||||
Timespans TimeSpans
|
||||
RatedUsage float64
|
||||
AccountSummary *AccountSummary
|
||||
deductConnectFee bool
|
||||
negativeConnectFee bool // the connect fee went negative on default balance
|
||||
maxCostDisconect bool
|
||||
|
||||
@@ -103,10 +103,11 @@ type CDR struct {
|
||||
ExtraFields map[string]string // Extra fields to be stored in CDR
|
||||
CostSource string // The source of this cost
|
||||
Cost float64
|
||||
CostDetails *CallCost // Attach the cost details to CDR when possible
|
||||
ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation
|
||||
Rated bool // Mark the CDR as rated so we do not process it during rating
|
||||
Partial bool // Used for partial record processing by CDRC
|
||||
CostDetails *CallCost // Attach the cost details to CDR when possible
|
||||
AccountSummary *AccountSummary // Store AccountSummary information
|
||||
ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation
|
||||
Rated bool // Mark the CDR as rated so we do not process it during rating
|
||||
Partial bool // Used for partial record processing by CDRC
|
||||
}
|
||||
|
||||
func (cdr *CDR) CostDetailsJson() string {
|
||||
|
||||
@@ -239,22 +239,27 @@ func (self *CdrServer) deriveRateStoreStatsReplicate(cdr *CDR, store, stats, rep
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store AccountSummary if requested
|
||||
if self.cgrCfg.CDRScdrAccountSummary {
|
||||
for _, ratedCDR := range ratedCDRs {
|
||||
if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID, utils.META_PSEUDOPREPAID, utils.PSEUDOPREPAID,
|
||||
utils.META_POSTPAID, utils.POSTPAID}, ratedCDR.RequestType) {
|
||||
acntID := utils.ConcatenatedKey(ratedCDR.Tenant, ratedCDR.Account)
|
||||
acnt, err := self.dataDB.GetAccount(acntID)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<CDRS> Querying AccountDigest for account: %s got error: %s", acntID, err.Error()))
|
||||
} else if acnt.ID != "" {
|
||||
ratedCDR.AccountSummary = acnt.AsAccountSummary()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store rated CDRs
|
||||
if store {
|
||||
for _, ratedCDR := range ratedCDRs {
|
||||
if ratedCDR.CostDetails != nil {
|
||||
ratedCDR.CostDetails.UpdateCost()
|
||||
ratedCDR.CostDetails.UpdateRatedUsage()
|
||||
if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID, utils.META_PSEUDOPREPAID, utils.PSEUDOPREPAID,
|
||||
utils.META_POSTPAID, utils.POSTPAID}, ratedCDR.RequestType) && self.cgrCfg.CDRScdrAccountSummary {
|
||||
acntID := utils.ConcatenatedKey(ratedCDR.Tenant, ratedCDR.Account)
|
||||
acnt, err := self.dataDB.GetAccount(acntID)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<CDRS> Querying AccountDigest for account: %s got error: %s", acntID, err.Error()))
|
||||
} else if acnt.ID != "" {
|
||||
ratedCDR.CostDetails.AccountSummary = acnt.AsAccountSummary()
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := self.cdrDb.SetCDR(ratedCDR, true); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<CDRS> Storing rated CDR %+v, got error: %s", ratedCDR, err.Error()))
|
||||
|
||||
@@ -423,6 +423,7 @@ type TBLCDRs struct {
|
||||
Cost float64
|
||||
CostDetails string
|
||||
CostSource string
|
||||
AccountSummary string
|
||||
ExtraInfo string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
@@ -675,6 +675,7 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error {
|
||||
CostSource: cdr.CostSource,
|
||||
Cost: cdr.Cost,
|
||||
CostDetails: cdr.CostDetailsJson(),
|
||||
AccountSummary: utils.ToJSON(cdr.AccountSummary),
|
||||
ExtraInfo: cdr.ExtraInfo,
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
@@ -707,6 +708,7 @@ func (self *SQLStorage) SetCDR(cdr *CDR, allowUpdate bool) error {
|
||||
CostSource: cdr.CostSource,
|
||||
Cost: cdr.Cost,
|
||||
CostDetails: cdr.CostDetailsJson(),
|
||||
AccountSummary: utils.ToJSON(cdr.AccountSummary),
|
||||
ExtraInfo: cdr.ExtraInfo,
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
@@ -975,6 +977,10 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR,
|
||||
return nil, 0, fmt.Errorf("JSON unmarshal callcost error for cgrid: %s, runid: %v, error: %s", result.Cgrid, result.RunID, err.Error())
|
||||
}
|
||||
}
|
||||
acntSummary, err := NewAccountSummaryFromJSON(result.AccountSummary)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("JSON unmarshal account summary error for cgrid: %s, runid: %v, error: %s", result.Cgrid, result.RunID, err.Error())
|
||||
}
|
||||
usageDur := time.Duration(result.Usage * utils.NANO_MULTIPLIER)
|
||||
pddDur := time.Duration(result.Pdd * utils.NANO_MULTIPLIER)
|
||||
storCdr := &CDR{
|
||||
@@ -1002,6 +1008,7 @@ func (self *SQLStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR,
|
||||
CostSource: result.CostSource,
|
||||
Cost: result.Cost,
|
||||
CostDetails: &callCost,
|
||||
AccountSummary: acntSummary,
|
||||
ExtraInfo: result.ExtraInfo,
|
||||
}
|
||||
cdrs = append(cdrs, storCdr)
|
||||
|
||||
@@ -703,3 +703,9 @@ func TestMaskSuffix(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestToJSON(t *testing.T) {
|
||||
if outNilObj := ToJSON(nil); outNilObj != "null" {
|
||||
t.Errorf("Expecting null, received: <%q>", outNilObj)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user