SureTax implementation completed, fixes #186

This commit is contained in:
DanB
2015-10-28 19:10:40 +01:00
parent 7d909ae577
commit 6f6ac784f8
7 changed files with 51 additions and 28 deletions

View File

@@ -292,6 +292,7 @@ const CGRATES_CFG_JSON = `
"url": "", // API url
"client_number": "", // client number, provided by SureTax
"validation_key": "", // validation key provided by SureTax
"business_unit": "", // clients Business Unit
"timezone": "Local", // convert the time of the events to this timezone before sending request out <UTC|Local|$IANA_TZ_DB>
"include_local_cost": false, // sum local calculated cost with tax one in final cost
"return_file_code": "0", // default or Quote purposes <0|Q>

View File

@@ -478,6 +478,7 @@ func TestDfSureTaxJsonCfg(t *testing.T) {
Url: utils.StringPointer(""),
Client_number: utils.StringPointer(""),
Validation_key: utils.StringPointer(""),
Business_unit: utils.StringPointer(""),
Timezone: utils.StringPointer("Local"),
Include_local_cost: utils.BoolPointer(false),
Return_file_code: utils.StringPointer("0"),

View File

@@ -269,6 +269,7 @@ type SureTaxJsonCfg struct {
Url *string
Client_number *string
Validation_key *string
Business_unit *string
Timezone *string
Include_local_cost *bool
Return_file_code *string

View File

@@ -46,6 +46,7 @@ type SureTaxCfg struct {
Url string
ClientNumber string
ValidationKey string
BusinessUnit string
Timezone *time.Location // Convert the time of the events to this timezone before sending request out
IncludeLocalCost bool
ReturnFileCode string
@@ -82,6 +83,9 @@ func (self *SureTaxCfg) loadFromJsonCfg(jsnCfg *SureTaxJsonCfg) error {
if jsnCfg.Validation_key != nil {
self.ValidationKey = *jsnCfg.Validation_key
}
if jsnCfg.Business_unit != nil {
self.BusinessUnit = *jsnCfg.Business_unit
}
if jsnCfg.Timezone != nil {
if self.Timezone, err = time.LoadLocation(*jsnCfg.Timezone); err != nil {
return err

View File

@@ -53,7 +53,7 @@ func NewSureTaxRequest(cdr *StoredCdr, stCfg *config.SureTaxCfg) (*SureTaxReques
}
stReq := new(STRequest)
stReq.ClientNumber = stCfg.ClientNumber
stReq.BusinessUnit = "" // Export it to config
stReq.BusinessUnit = stCfg.BusinessUnit
stReq.ValidationKey = stCfg.ValidationKey
stReq.DataYear = strconv.Itoa(aTimeLoc.Year())
stReq.DataMonth = strconv.Itoa(int(aTimeLoc.Month()))
@@ -85,11 +85,21 @@ func NewSureTaxRequest(cdr *StoredCdr, stCfg *config.SureTaxCfg) (*SureTaxReques
TaxExemptionCodeList: taxExempt,
},
}
return &SureTaxRequest{Request: stReq}, nil
jsnContent, err := json.Marshal(stReq)
if err != nil {
return nil, err
}
return &SureTaxRequest{Request: string(jsnContent)}, nil
}
// SureTax JSON Request
type SureTaxRequest struct {
Request *STRequest // SureTax Requires us to encapsulate the content into a request element
Request string `json:"request"` // SureTax Requires us to encapsulate the content into a request element
}
// SureTax JSON Response
type SureTaxResponse struct {
D string // SureTax requires encapsulating reply into a D object
}
// SureTax Request type
@@ -133,18 +143,13 @@ type STRequestItem struct {
TaxExemptionCodeList []string // Required. Tax Exemption to be applied to this item only.
}
// SureTax Response type
type SureTaxResponse struct {
D *STResponse // SureTax requires encapsulating reply into a D object
}
type STResponse struct {
Successful string // Response will be either Y' or N' : Y = Success / Success with Item error N = Failure
ResponseCode int64 // ResponseCode: 9999 Request was successful. 1101-1400 Range of values for a failed request (no processing occurred) 9001 Request was successful, but items within the request have errors. The specific items with errors are provided in the ItemMessages field.
ResponseCode string // ResponseCode: 9999 Request was successful. 1101-1400 Range of values for a failed request (no processing occurred) 9001 Request was successful, but items within the request have errors. The specific items with errors are provided in the ItemMessages field.
HeaderMessage string // Response message: For ResponseCode 9999 “Success”For ResponseCode 9001 “Success with Item errors”. For ResponseCode 1100-1400 Unsuccessful / declined web request.
ItemMessages []*STItemMessage // This field contains a list of items that were not able to be processed due to bad or invalid data (see Response Code of “9001”).
ClientTracking string // Client transaction tracking provided in web request.
TotalTax float64 // Total Tax a total of all taxes included in the TaxList
TotalTax string // Total Tax a total of all taxes included in the TaxList
TransId int // Transaction ID provided by SureTax
GroupList []*STGroup // contains one-to-many Groups
}
@@ -166,9 +171,9 @@ type STGroup struct {
// Part of the SureTax Response
type STTaxItem struct {
TaxTypeCode string // Tax Type Code
TaxTypeDesc string // Tax Type Description
TaxAmount float64 // Tax Amount
TaxTypeCode string // Tax Type Code
TaxTypeDesc string // Tax Type Description
TaxAmount string // Tax Amount
}
func SureTaxProcessCdr(cdr *StoredCdr) error {
@@ -198,30 +203,38 @@ func SureTaxProcessCdr(cdr *StoredCdr) error {
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
utils.Logger.Debug(fmt.Sprintf("Unexpected response body received, error: %s\n", err.Error()))
//utils.Logger.Debug(fmt.Sprintf("Unexpected response body received, error: %s\n", err.Error()))
return err
}
if resp.StatusCode > 299 {
utils.Logger.Debug(fmt.Sprintf("Unexpected code received: %d\n", resp.StatusCode))
//utils.Logger.Debug(fmt.Sprintf("Unexpected code received: %d\n", resp.StatusCode))
return fmt.Errorf("Unexpected status code received: %d", resp.StatusCode)
}
utils.Logger.Debug(fmt.Sprintf("Received raw answer from SureTax: %s\n", string(respBody)))
var stResp SureTaxResponse
if err := json.Unmarshal(respBody, &stResp); err != nil {
//utils.Logger.Debug(fmt.Sprintf("Received raw answer from SureTax: %s\n", string(respBody)))
var respFull SureTaxResponse
if err := json.Unmarshal(respBody, &respFull); err != nil {
return err
}
utils.Logger.Debug(fmt.Sprintf("Received answer from SureTax: %+v\n", stResp))
if stResp.D.ResponseCode != 9999 {
cdr.ExtraInfo = stResp.D.HeaderMessage
//utils.Logger.Debug(fmt.Sprintf("Received answer from SureTax: %+v\n", respFull))
var stResp STResponse
if err := json.Unmarshal([]byte(respFull.D), &stResp); err != nil {
return err
}
if stResp.ResponseCode != "9999" {
cdr.ExtraInfo = stResp.HeaderMessage
return nil // No error because the request was processed by SureTax, error will be in the ExtraInfo
}
// Write cost to CDR
totalTax, err := strconv.ParseFloat(stResp.TotalTax, 64)
if err != nil {
cdr.ExtraInfo = err.Error()
}
if !stCfg.IncludeLocalCost {
cdr.Cost = utils.Round(stResp.D.TotalTax, config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE)
cdr.Cost = utils.Round(totalTax, config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE)
} else {
cdr.Cost = utils.Round(cdr.Cost+stResp.D.TotalTax, config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE)
cdr.Cost = utils.Round(cdr.Cost+totalTax, config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE)
}
// Add response into extra fields to be available for later review
cdr.ExtraFields[utils.META_SURETAX] = string(respBody)
cdr.ExtraFields[utils.META_SURETAX] = respFull.D
return nil
}

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"encoding/json"
"reflect"
"testing"
"time"
@@ -40,7 +41,7 @@ func TestNewSureTaxRequest(t *testing.T) {
stCfg.ClientNumber = "000000000"
stCfg.ValidationKey = "19491161-F004-4F44-BDB3-E976D6739A64"
stCfg.Timezone = time.UTC
eSureTaxRequest := &SureTaxRequest{Request: &STRequest{
eSTRequest := &STRequest{
ClientNumber: "000000000",
ValidationKey: "19491161-F004-4F44-BDB3-E976D6739A64",
DataYear: "2013",
@@ -69,10 +70,12 @@ func TestNewSureTaxRequest(t *testing.T) {
TaxExemptionCodeList: []string{},
},
},
}}
}
jsnReq, _ := json.Marshal(eSTRequest)
eSureTaxRequest := &SureTaxRequest{Request: string(jsnReq)}
if stReq, err := NewSureTaxRequest(cdr, stCfg); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eSureTaxRequest, stReq) {
t.Errorf("Expecting: %+v, received: %+v", eSureTaxRequest.Request.ItemList[0], stReq.Request.ItemList[0])
t.Errorf("Expecting: %s, received: %s", string(eSureTaxRequest.Request), string(stReq.Request))
}
}

View File

@@ -169,7 +169,7 @@ func TestSTIGetCdrs(t *testing.T) {
} else if len(cdrs) != 1 {
t.Error("Unexpected number of CDRs returned: ", len(cdrs))
} else {
if cdrs[0].Cost != 0.012 {
if cdrs[0].Cost != 0.0027 {
t.Errorf("Unexpected Cost for CDR: %+v", cdrs[0])
}
}