diff --git a/combine.go b/combine.go index 5fb80a1..b954167 100644 --- a/combine.go +++ b/combine.go @@ -113,12 +113,14 @@ func CombineCallCDRs(cdrLines []Line, prices []Price) ([]Call, error) { destinationToPrice[CALL_NATIONAL_DESTINATION_AIRTIME_FROM_HANDSET.Destination] = CALL_NATIONAL_DESTINATION_AIRTIME_FROM_HANDSET destinationToPrice[CALL_NATIONAL_DESTINATION_MOBILE.Destination] = CALL_NATIONAL_DESTINATION_MOBILE + nonMatchedDestinations := make(map[string]struct{}) for _, l := range cdrLines { if l.Kind != VoiceLine { continue } // Cache destination prices - if _, ok := destinationToPrice[l.Destination]; !ok { + _, knownNonPriced := nonMatchedDestinations[l.Destination] + if _, ok := destinationToPrice[l.Destination]; !ok && !knownNonPriced { priceLoop: for _, p := range prices { if p.Type != PriceCall { @@ -128,10 +130,15 @@ func CombineCallCDRs(cdrLines []Line, prices []Price) ([]Call, error) { destinationToPrice[l.Destination] = p break priceLoop } + nonMatchedDestinations[l.Destination] = struct{}{} } } } + for k := range nonMatchedDestinations { + fmt.Printf("[warning] no price for destination %v\n", k) + } + // a map from "%s_%s_%s": l.Time.Format(DateTimeFormat), l.CLI, l.From uniqueCalls := make(map[string][]Line) for _, l := range cdrLines { @@ -147,7 +154,7 @@ func CombineCallCDRs(cdrLines []Line, prices []Price) ([]Call, error) { ret := make([]Call, len(uniqueCalls)) i := 0 - for k, v := range uniqueCalls { + for _, v := range uniqueCalls { /* fmt.Printf("[%s] %d\n", k, len(v)) for i, c := range v { @@ -155,47 +162,63 @@ func CombineCallCDRs(cdrLines []Line, prices []Price) ([]Call, error) { } fmt.Println() */ - var legPrice Price for _, leg := range v { - switch { - // HS -> PBX (non-roaming) - case l.CLI == l.From && l.Source == CALL_FROM_HANDSET_SOURCE && l.Destination == CALL_FROM_HANDSET_DESTINATION: - // This leg consists of the airtime (outgoing call from the HS perspective) - legPrice = CALL_NATIONAL_DESTINATION_AIRTIME_FROM_HANDSET - // PBX -> HS (roaming + non-roaming) - case l.From == l.To && l.Source == CALL_TO_HANDSET_SOURCE && l.Destination == CALL_TO_HANDSET_DESTINATION: - // This leg consists of the airtime - legPrice = CALL_NATIONAL_DESTINATION_AIRTIME_TO_HANDSET - // PBX -> destination, HS -> destination (non-roaming) - case l.CLI == l.From && l.From != l.To && l.Source == CALL_FROM_PBX_SOURCE: - // This leg consists of routing a call from a PBX through our platform - fallthrough - case l.CLI == l.From && l.From != l.To && l.Source == CALL_FROM_HANDSET_SOURCE: - // The costs are defined by the call's destination - legPrice = destinationToPrice[l.Destination] - // HS -> destination (roaming), HS -> PBX (roaming) - case l.CLI == l.From && l.Source != CALL_FROM_HANDSET_SOURCE && l.Reason == ORIG: - - // source -> HS (roaming) - case l.CLI != l.From && l.Source == CALL_TO_HANDSET_SOURCE && l.Reason == ROAM: - // We only know the destination country - - // Source -> HS (non-roaming) (i.e. incoming calls) does not exist in the CSV - default: + legPrice := Price{} + if leg.CLI == leg.From { + switch { + case leg.Source == CALL_FROM_HANDSET_SOURCE && leg.Destination == CALL_FROM_HANDSET_DESTINATION: + // This leg consists of the airtime (outgoing call from the HS perspective) (HS->PBX, non-roaming) + legPrice = CALL_NATIONAL_DESTINATION_AIRTIME_FROM_HANDSET + + case leg.From != leg.To && leg.Source == CALL_FROM_HANDSET_SOURCE: // Case 2, 3 + // This leg consists of routing a call (from a PBX or Handset) through our platform. The costs are defined by the call's destination. + // Case 1: PBX->destination + // Case 2: HS->destination, non roaming + // Case 3: HS->destination, roaming + // Case 4: HS->PBX, roaming + fallthrough + case leg.Source != CALL_FROM_HANDSET_SOURCE && leg.Reason == ORIG: // Case 1 + fallthrough + case leg.From != leg.To && leg.Source == CALL_FROM_PBX_SOURCE: // Case 4 + legPrice = destinationToPrice[leg.Destination] + } + } + if leg.CLI != leg.From { + switch { + case leg.From == leg.To && leg.Source == CALL_TO_HANDSET_SOURCE && leg.Destination == CALL_TO_HANDSET_DESTINATION: + // This leg consists of the airtime (PBX->HS, roaming + non-roaming) + legPrice = CALL_NATIONAL_DESTINATION_AIRTIME_TO_HANDSET + // source -> HS (roaming) + case leg.Source == CALL_TO_HANDSET_SOURCE && leg.Reason == ROAM: + // We only know the destination country + fallthrough + case leg.CLI == CALL_CLI_ANONYMOUS: + // Incoming call from a blocked CLI + legPrice = destinationToPrice[leg.Destination] + } } - fmt.Printf("(%12s->%12s) leg %d, price: %+v\n", l.CLI, l.To, l.Leg, legPrice) + if legPrice == (Price{}) { + // error, weird category + _, mapOk := destinationToPrice[leg.Destination] + fmt.Printf("[warning] non-matched CDR leg (cid: %q, dt: %v, CLI: %s, %s->%s, src: %s, dest: %s (%s) %v\n", + leg.Id, leg.Time.Format(DateTimeFormat), leg.CLI, leg.From, leg.To, leg.Source, leg.Destination, leg.Reason, mapOk) + } + // Source -> HS (non-roaming) (i.e. incoming calls) does not exist in the CSV + fmt.Printf("(%12s->%12s) leg %d, price: %+v\n", leg.CLI, leg.To, leg.Leg, legPrice) } ret[i] = Call{ From: "asdf", To: "asdkflj", - Duration: time.Duration{}, + Duration: time.Duration(0), Cost: 0, Price: 0, } - ret[i].Legs = make([]PricedLine, len(v)) - for j, leg := range v { - ret[i].Legs[j] = leg - } + /* + ret[i].Legs = make([]PricedLine, len(v)) + for j, leg := range v { + ret[i].Legs[j] = leg + } + */ i++ }