@ -2,22 +2,32 @@ package telecom
import (
"bytes"
"database/sql"
"encoding/csv"
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"time"
)
/ *
First step is building the reports on verizon ' s website . Below are the columns ( and hopefully categories ) that you need
to completely recreate the report .
VerizonCallLine ( report structure ) :
Wireless number [ mandatory ]
"User name" [ Contact Information ]
Date [ Voice Usage ]
Minutes [ voice usage ]
Number [ voice usage ]
Usage Type [ mandatory ]
VerizonSMSLine ( report structure ) :
Wireless number [ mandatory ]
Message date / time [ Messaging usage ]
to / from wireless number [ Messaging usage ]
The report comes as a comma / LF formatted CSV . It has 13 lines of useless header data and 1 line of useless total data
@ -25,6 +35,36 @@ that must be trimmed off to shove everything through a struct factory.
* /
var VerizonCallLineDBMappingFunction = func ( s * sql . Stmt , item * VerizonCallLine ) {
_ , err := s . Exec (
item . WirelessNumber ,
item . CallDate ,
item . CallMinutes ,
item . OtherNumber ,
)
if err != nil {
log . Printf ( "%#v\n" , s )
log . Panic ( err )
}
}
var VerizonSmsLineDBMappingFunction = func ( s * sql . Stmt , item * VerizonSMSLine ) {
_ , err := s . Exec (
item . WirelessNumber ,
item . MsgDateTime ,
item . OtherNumber ,
)
if err != nil {
log . Printf ( "%#v\n" , s )
log . Panic ( err )
}
}
const (
verizonCallHeaderLineCount = 14
verizonSMSHeaderLineCount = 14
)
type (
VerizonCSV struct {
trimmed bool
@ -34,23 +74,62 @@ type (
VerizonCallLine struct {
WirelessNumber string
UserName string
CallDate string
CallMinutes int
OtherNumber string
UsageCategory string
}
VerizonSMSLine struct {
WirelessNumber string
MsgDateTime string
OtherNumber string
}
)
func RowToVerizonCallLine ( row [ ] string ) * VerizonCallLine {
minutes , err := strconv . Atoi ( row [ 3 ] )
minutes , err := strconv . Atoi ( row [ 2 ] )
if err != nil {
fmt . Printf ( "%#v\n" , row )
panic ( err )
}
line := VerizonCallLine { row [ 0 ] , row [ 1 ] , row [ 2 ] , minutes , row [ 4 ] , row [ 5 ] }
line := VerizonCallLine { row [ 0 ] , convertDateField ( row [ 1 ] ) , minutes , convertSolidPhoneNumberToDashes ( row [ 3 ] ) }
return & line
}
func RowToVerizonSMSLine ( row [ ] string ) * VerizonSMSLine {
line := VerizonSMSLine { row [ 0 ] , convertDateTimeField ( row [ 1 ] ) , row [ 2 ] }
return & line
}
func VerizonCallDataFilter ( row [ ] string ) bool {
return len ( row [ 2 ] ) > 0
}
func VerizonSMSDataFilter ( row [ ] string ) bool {
return len ( row [ 2 ] ) > 0
}
func convertDateField ( d string ) string {
parts := strings . Split ( d , "/" )
return fmt . Sprintf ( "%s-%s-%s" , parts [ 2 ] , parts [ 0 ] , parts [ 1 ] )
}
func convertDateTimeField ( dt string ) string {
dateTime , err := time . Parse ( "1/2/06 3:04 PM" , dt )
if err != nil {
panic ( err )
}
return dateTime . Add ( - 4 * time . Hour ) . Format ( "2006-01-02 15:04:05.000000" )
}
func convertSolidPhoneNumberToDashes ( str string ) string {
if len ( str ) < 10 {
return ""
}
return fmt . Sprintf ( "%s-%s-%s" , str [ 0 : 3 ] , str [ 3 : 6 ] , str [ 6 : 10 ] )
}
func NewVerizonCSV ( pathlike string ) * VerizonCSV {
csv := VerizonCSV { trimmed : false }
file , err := os . OpenFile ( pathlike , os . O_RDONLY , 777 )
@ -81,17 +160,22 @@ func (v *VerizonCSV) trimHeadersAndFooters() {
for i , c := range data {
if c == '\n' {
lineCount += 1
if lineCount == 13 {
if lineCount == verizonCallHeaderLineCount {
headerIdx = i + 1
break
}
}
}
lastRowFound := false
for i := len ( data ) - 1 ; i >= 0 ; i -- {
c := data [ i ]
if c == 'n' {
footerIdx = i + 1
break
if c == '\n' {
if lastRowFound {
footerIdx = i + 1
break
}
lastRowFound = true
}
}
@ -101,7 +185,7 @@ func (v *VerizonCSV) trimHeadersAndFooters() {
}
func ProcessVerizonCsvToObjects [ K any ] ( v * VerizonCSV , mappingFunction func ( [ ] string ) * K , filterFunction func ( [ ] string ) bool ) * [ ] * K {
ret := make ( [ ] * K , 0 , 1000 )
ret := make ( [ ] * K , 0 , 1000 0 )
doc := csv . NewReader ( v . TabularData )
var filter func ( [ ] string ) bool
@ -123,3 +207,11 @@ func ProcessVerizonCsvToObjects[K any](v *VerizonCSV, mappingFunction func([]str
return & ret
}
func ( call VerizonCallLine ) ToQueryBlock ( ) string {
return fmt . Sprintf ( "('%s','%s',%d,'%s')" , call . WirelessNumber , call . CallDate , call . CallMinutes , call . OtherNumber )
}
func ( sms VerizonSMSLine ) ToQueryBlock ( ) string {
return fmt . Sprintf ( "('%s','%s','%s')" , sms . WirelessNumber , sms . MsgDateTime , sms . OtherNumber )
}