mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-17 22:29:55 +05:00
Improved SureTax configuration with defaults, modified NewSureTaxRequest method
This commit is contained in:
@@ -31,15 +31,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DISABLED = "disabled"
|
||||
JSON = "json"
|
||||
GOB = "gob"
|
||||
POSTGRES = "postgres"
|
||||
MONGO = "mongo"
|
||||
REDIS = "redis"
|
||||
SAME = "same"
|
||||
FS = "freeswitch"
|
||||
CFG_RELOADS = "cfg_reloads_"
|
||||
DISABLED = "disabled"
|
||||
JSON = "json"
|
||||
GOB = "gob"
|
||||
POSTGRES = "postgres"
|
||||
MONGO = "mongo"
|
||||
REDIS = "redis"
|
||||
SAME = "same"
|
||||
FS = "freeswitch"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -70,6 +69,8 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
|
||||
cfg.ConfigReloads[utils.CDRC] <- struct{}{} // Unlock the channel
|
||||
cfg.ConfigReloads[utils.CDRE] = make(chan struct{}, 1)
|
||||
cfg.ConfigReloads[utils.CDRE] <- struct{}{} // Unlock the channel
|
||||
cfg.ConfigReloads[utils.SURETAX] = make(chan struct{}, 1)
|
||||
cfg.ConfigReloads[utils.SURETAX] <- struct{}{} // Unlock the channel
|
||||
cgrJsonCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -238,8 +239,8 @@ type CGRConfig struct {
|
||||
MailerAuthUser string // Authenticate to email server using this user
|
||||
MailerAuthPass string // Authenticate to email server with this password
|
||||
MailerFromAddr string // From address used when sending emails out
|
||||
SureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future
|
||||
DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options
|
||||
sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future
|
||||
ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur
|
||||
// Cache defaults loaded from json and needing clones
|
||||
dfltCdreProfile *CdreConfig // Default cdreConfig profile
|
||||
@@ -804,35 +805,22 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
}
|
||||
}
|
||||
|
||||
if jsnSureTaxCfg != nil {
|
||||
self.SureTaxCfg = new(SureTaxCfg) // Reset previous values
|
||||
if jsnSureTaxCfg.Url != nil {
|
||||
self.SureTaxCfg.Url = *jsnSureTaxCfg.Url
|
||||
if jsnSureTaxCfg != nil { // New config for SureTax
|
||||
if self.sureTaxCfg, err = NewSureTaxCfgWithDefaults(); err != nil {
|
||||
return err
|
||||
}
|
||||
if jsnSureTaxCfg.Client_number != nil {
|
||||
self.SureTaxCfg.ClientNumber = *jsnSureTaxCfg.Client_number
|
||||
}
|
||||
if jsnSureTaxCfg.Validation_key != nil {
|
||||
self.SureTaxCfg.ValidationKey = *jsnSureTaxCfg.Validation_key
|
||||
}
|
||||
if jsnSureTaxCfg.Timezone != nil {
|
||||
if self.SureTaxCfg.Timezone, err = time.LoadLocation(*jsnSureTaxCfg.Timezone); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnSureTaxCfg.Include_local_cost != nil {
|
||||
self.SureTaxCfg.IncludeLocalCost = *jsnSureTaxCfg.Include_local_cost
|
||||
}
|
||||
if jsnSureTaxCfg.Origination_number != nil {
|
||||
if self.SureTaxCfg.OriginationNumber, err = utils.ParseRSRFields(*jsnSureTaxCfg.Origination_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnSureTaxCfg.Termination_number != nil {
|
||||
if self.SureTaxCfg.TerminationNumber, err = utils.ParseRSRFields(*jsnSureTaxCfg.Termination_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := self.sureTaxCfg.loadFromJsonCfg(jsnSureTaxCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use locking to retrieve the configuration, possibility later for runtime reload
|
||||
func (self *CGRConfig) SureTaxCfg() *SureTaxCfg {
|
||||
cfgChan := <-self.ConfigReloads[utils.SURETAX] // Lock config for read or reloads
|
||||
stCfg := self.sureTaxCfg
|
||||
self.ConfigReloads[utils.SURETAX] <- cfgChan // unlock config for reloads or read
|
||||
return stCfg
|
||||
}
|
||||
|
||||
@@ -280,13 +280,31 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
|
||||
"suretax": {
|
||||
"url": "", // API url
|
||||
"client_number": "", // client number, provided by SureTax
|
||||
"validation_key": "", // validation key provided by SureTax
|
||||
"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
|
||||
"origination_number": "Subject", // template extracting origination number out of StoredCdr
|
||||
"termination_number": "Destination", // template extracting termination number out of StoredCdr
|
||||
"url": "", // API url
|
||||
"client_number": "", // client number, provided by SureTax
|
||||
"validation_key": "", // validation key provided by SureTax
|
||||
"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>
|
||||
"response_group": "03", // determines how taxes are grouped for the response <03|13>
|
||||
"response_type": "D4", // determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response
|
||||
"regulatory_code": "03", // provider type
|
||||
"client_tracking": "CgrId", // template extracting client information out of StoredCdr; <$RSRFields>
|
||||
"customer_number": "CustomerNumber", // template extracting customer number out of StoredCdr; <$RSRFields>
|
||||
"orig_number": "Subject", // template extracting origination number out of StoredCdr; <$RSRFields>
|
||||
"term_number": "Destination", // template extracting termination number out of StoredCdr; <$RSRFields>
|
||||
"bill_to_number": "", // template extracting billed to number out of StoredCdr; <$RSRFields>
|
||||
"zipcode": "", // template extracting billing zip code out of StoredCdr; <$RSRFields>
|
||||
"plus4": "", // template extracting billing zip code extension out of StoredCdr; <$RSRFields>
|
||||
"p2pzipcode": "", // template extracting secondary zip code out of StoredCdr; <$RSRFields>
|
||||
"p2pplus4": "", // template extracting secondary zip code extension out of StoredCdr; <$RSRFields>
|
||||
"units": "^1", // template extracting number of “lines” or unique charges contained within the revenue out of StoredCdr; <$RSRFields>
|
||||
"unit_type": "^00", // template extracting number of unique access lines out of StoredCdr; <$RSRFields>
|
||||
"tax_included": "^0", // template extracting tax included in revenue out of StoredCdr; <$RSRFields>
|
||||
"tax_situs_rule": "^04", // template extracting tax situs rule out of StoredCdr; <$RSRFields>
|
||||
"trans_type_code": "^010101", // template extracting transaction type indicator out of StoredCdr; <$RSRFields>
|
||||
"sales_type_code": "^R", // template extracting sales type code out of StoredCdr; <$RSRFields>
|
||||
"tax_exemption_code_list": "", // template extracting tax exemption code list out of StoredCdr; <$RSRFields>
|
||||
},
|
||||
|
||||
}`
|
||||
|
||||
@@ -459,13 +459,31 @@ func TestDfMailerJsonCfg(t *testing.T) {
|
||||
|
||||
func TestDfSureTaxJsonCfg(t *testing.T) {
|
||||
eCfg := &SureTaxJsonCfg{
|
||||
Url: utils.StringPointer(""),
|
||||
Client_number: utils.StringPointer(""),
|
||||
Validation_key: utils.StringPointer(""),
|
||||
Timezone: utils.StringPointer("Local"),
|
||||
Include_local_cost: utils.BoolPointer(false),
|
||||
Origination_number: utils.StringPointer("Subject"),
|
||||
Termination_number: utils.StringPointer("Destination"),
|
||||
Url: utils.StringPointer(""),
|
||||
Client_number: utils.StringPointer(""),
|
||||
Validation_key: utils.StringPointer(""),
|
||||
Timezone: utils.StringPointer("Local"),
|
||||
Include_local_cost: utils.BoolPointer(false),
|
||||
Return_file_code: utils.StringPointer("0"),
|
||||
Response_group: utils.StringPointer("03"),
|
||||
Response_type: utils.StringPointer("D4"),
|
||||
Regulatory_code: utils.StringPointer("03"),
|
||||
Client_tracking: utils.StringPointer("CgrId"),
|
||||
Customer_number: utils.StringPointer("CustomerNumber"),
|
||||
Orig_number: utils.StringPointer("Subject"),
|
||||
Term_number: utils.StringPointer("Destination"),
|
||||
Bill_to_number: utils.StringPointer(""),
|
||||
Zipcode: utils.StringPointer(""),
|
||||
Plus4: utils.StringPointer(""),
|
||||
P2PZipcode: utils.StringPointer(""),
|
||||
P2PPlus4: utils.StringPointer(""),
|
||||
Units: utils.StringPointer("^1"),
|
||||
Unit_type: utils.StringPointer("^00"),
|
||||
Tax_included: utils.StringPointer("^0"),
|
||||
Tax_situs_rule: utils.StringPointer("^04"),
|
||||
Trans_type_code: utils.StringPointer("^010101"),
|
||||
Sales_type_code: utils.StringPointer("^R"),
|
||||
Tax_exemption_code_list: utils.StringPointer(""),
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.SureTaxJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CdrReplicationCfg struct {
|
||||
@@ -36,13 +35,3 @@ type CdrReplicationCfg struct {
|
||||
func (rplCfg CdrReplicationCfg) FallbackFileName() string {
|
||||
return fmt.Sprintf("cdr_%s_%s_%s.form", rplCfg.Transport, url.QueryEscape(rplCfg.Server), utils.GenUUID())
|
||||
}
|
||||
|
||||
type SureTaxCfg struct {
|
||||
Url string
|
||||
ClientNumber string
|
||||
ValidationKey string
|
||||
Timezone *time.Location // Convert the time of the events to this timezone before sending request out
|
||||
IncludeLocalCost bool
|
||||
OriginationNumber utils.RSRFields // Concatenate all of them to get value
|
||||
TerminationNumber utils.RSRFields // Concatenate all of them to get value
|
||||
}
|
||||
|
||||
@@ -256,11 +256,29 @@ type MailerJsonCfg struct {
|
||||
|
||||
// SureTax config section
|
||||
type SureTaxJsonCfg struct {
|
||||
Url *string // API url
|
||||
Client_number *string // client number provided by SureTax
|
||||
Validation_key *string // validation key provided by SureTax
|
||||
Timezone *string // convert the time of the events to this timezone before sending request out
|
||||
Include_local_cost *bool // sum local calculated cost with tax one
|
||||
Origination_number *string // template extracting origination number out of StoredCdr
|
||||
Termination_number *string // template extracting origination number out of StoredCdr
|
||||
Url *string
|
||||
Client_number *string
|
||||
Validation_key *string
|
||||
Timezone *string
|
||||
Include_local_cost *bool
|
||||
Return_file_code *string
|
||||
Response_group *string
|
||||
Response_type *string
|
||||
Regulatory_code *string
|
||||
Client_tracking *string
|
||||
Customer_number *string
|
||||
Orig_number *string
|
||||
Term_number *string
|
||||
Bill_to_number *string
|
||||
Zipcode *string
|
||||
Plus4 *string
|
||||
P2PZipcode *string
|
||||
P2PPlus4 *string
|
||||
Units *string
|
||||
Unit_type *string
|
||||
Tax_included *string
|
||||
Tax_situs_rule *string
|
||||
Trans_type_code *string
|
||||
Sales_type_code *string
|
||||
Tax_exemption_code_list *string
|
||||
}
|
||||
|
||||
186
config/suretaxconfig.go
Normal file
186
config/suretaxconfig.go
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Creates a new SureTaxCfg with defaults pre-populated out of config_defaults.json
|
||||
func NewSureTaxCfgWithDefaults() (*SureTaxCfg, error) {
|
||||
jsnCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsnSureTaxCfg, err := jsnCfg.SureTaxJsonCfg()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := new(SureTaxCfg)
|
||||
if err := st.loadFromJsonCfg(jsnSureTaxCfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// SureTax configuration object
|
||||
type SureTaxCfg struct {
|
||||
Url string
|
||||
ClientNumber string
|
||||
ValidationKey string
|
||||
Timezone *time.Location // Convert the time of the events to this timezone before sending request out
|
||||
IncludeLocalCost bool
|
||||
ReturnFileCode string
|
||||
ResponseGroup string
|
||||
ResponseType string
|
||||
RegulatoryCode string
|
||||
ClientTracking utils.RSRFields // Concatenate all of them to get value
|
||||
CustomerNumber utils.RSRFields
|
||||
OrigNumber utils.RSRFields
|
||||
TermNumber utils.RSRFields
|
||||
BillToNumber utils.RSRFields
|
||||
Zipcode utils.RSRFields
|
||||
Plus4 utils.RSRFields
|
||||
P2PZipcode utils.RSRFields
|
||||
P2PPlus4 utils.RSRFields
|
||||
Units utils.RSRFields
|
||||
UnitType utils.RSRFields
|
||||
TaxIncluded utils.RSRFields
|
||||
TaxSitusRule utils.RSRFields
|
||||
TransTypeCode utils.RSRFields
|
||||
SalesTypeCode utils.RSRFields
|
||||
TaxExemptionCodeList utils.RSRFields
|
||||
}
|
||||
|
||||
// Loads/re-loads data from json config object
|
||||
func (self *SureTaxCfg) loadFromJsonCfg(jsnCfg *SureTaxJsonCfg) error {
|
||||
var err error
|
||||
if jsnCfg.Url != nil {
|
||||
self.Url = *jsnCfg.Url
|
||||
}
|
||||
if jsnCfg.Client_number != nil {
|
||||
self.ClientNumber = *jsnCfg.Client_number
|
||||
}
|
||||
if jsnCfg.Validation_key != nil {
|
||||
self.ValidationKey = *jsnCfg.Validation_key
|
||||
}
|
||||
if jsnCfg.Timezone != nil {
|
||||
if self.Timezone, err = time.LoadLocation(*jsnCfg.Timezone); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Include_local_cost != nil {
|
||||
self.IncludeLocalCost = *jsnCfg.Include_local_cost
|
||||
}
|
||||
if jsnCfg.Return_file_code != nil {
|
||||
self.ReturnFileCode = *jsnCfg.Return_file_code
|
||||
}
|
||||
if jsnCfg.Response_group != nil {
|
||||
self.ResponseGroup = *jsnCfg.Response_group
|
||||
}
|
||||
if jsnCfg.Response_type != nil {
|
||||
self.ResponseType = *jsnCfg.Response_type
|
||||
}
|
||||
if jsnCfg.Regulatory_code != nil {
|
||||
self.RegulatoryCode = *jsnCfg.Regulatory_code
|
||||
}
|
||||
if jsnCfg.Client_tracking != nil {
|
||||
if self.ClientTracking, err = utils.ParseRSRFields(*jsnCfg.Client_tracking, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Customer_number != nil {
|
||||
if self.CustomerNumber, err = utils.ParseRSRFields(*jsnCfg.Customer_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Orig_number != nil {
|
||||
if self.OrigNumber, err = utils.ParseRSRFields(*jsnCfg.Orig_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Term_number != nil {
|
||||
if self.TermNumber, err = utils.ParseRSRFields(*jsnCfg.Term_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Bill_to_number != nil {
|
||||
if self.BillToNumber, err = utils.ParseRSRFields(*jsnCfg.Bill_to_number, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Zipcode != nil {
|
||||
if self.Zipcode, err = utils.ParseRSRFields(*jsnCfg.Zipcode, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Plus4 != nil {
|
||||
if self.Plus4, err = utils.ParseRSRFields(*jsnCfg.Plus4, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.P2PZipcode != nil {
|
||||
if self.P2PZipcode, err = utils.ParseRSRFields(*jsnCfg.P2PZipcode, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.P2PPlus4 != nil {
|
||||
if self.P2PPlus4, err = utils.ParseRSRFields(*jsnCfg.P2PPlus4, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Units != nil {
|
||||
if self.Units, err = utils.ParseRSRFields(*jsnCfg.Units, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Unit_type != nil {
|
||||
if self.UnitType, err = utils.ParseRSRFields(*jsnCfg.Unit_type, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Tax_included != nil {
|
||||
if self.TaxIncluded, err = utils.ParseRSRFields(*jsnCfg.Tax_included, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Tax_situs_rule != nil {
|
||||
if self.TaxSitusRule, err = utils.ParseRSRFields(*jsnCfg.Tax_situs_rule, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Trans_type_code != nil {
|
||||
if self.TransTypeCode, err = utils.ParseRSRFields(*jsnCfg.Trans_type_code, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Sales_type_code != nil {
|
||||
if self.SalesTypeCode, err = utils.ParseRSRFields(*jsnCfg.Sales_type_code, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Tax_exemption_code_list != nil {
|
||||
if self.TaxExemptionCodeList, err = utils.ParseRSRFields(*jsnCfg.Tax_exemption_code_list, utils.INFIELD_SEP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -19,14 +19,89 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var sureTaxClient *http.Client // Cache the client here if in use
|
||||
|
||||
// Init a new request to be sent out to SureTax
|
||||
func NewSureTaxRequest(cdr *StoredCdr, stCfg *config.SureTaxCfg) (*SureTaxRequest, error) {
|
||||
aTimeLoc := cdr.AnswerTime.In(stCfg.Timezone)
|
||||
revenue := utils.Round(cdr.Cost, 4, utils.ROUNDING_MIDDLE)
|
||||
unts, err := strconv.ParseInt(cdr.FieldsAsString(stCfg.Units), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taxExempt := []string{}
|
||||
definedTaxExtempt := cdr.FieldsAsString(stCfg.TaxExemptionCodeList)
|
||||
if len(definedTaxExtempt) != 0 {
|
||||
taxExempt = strings.Split(cdr.FieldsAsString(stCfg.TaxExemptionCodeList), ",")
|
||||
}
|
||||
stReq := new(SureTaxRequest)
|
||||
stReq.ClientNumber = stCfg.ClientNumber
|
||||
stReq.BusinessUnit = "" // Export it to config
|
||||
stReq.ValidationKey = stCfg.ValidationKey
|
||||
stReq.DataYear = strconv.Itoa(aTimeLoc.Year())
|
||||
stReq.DataMonth = strconv.Itoa(int(aTimeLoc.Month()))
|
||||
stReq.TotalRevenue = revenue
|
||||
stReq.ReturnFileCode = stCfg.ReturnFileCode
|
||||
stReq.ClientTracking = cdr.FieldsAsString(stCfg.ClientTracking)
|
||||
stReq.ResponseGroup = stCfg.ResponseGroup
|
||||
stReq.ResponseType = stCfg.ResponseType
|
||||
stReq.ItemList = []*STRequestItem{
|
||||
&STRequestItem{
|
||||
CustomerNumber: cdr.FieldsAsString(stCfg.CustomerNumber),
|
||||
OrigNumber: cdr.FieldsAsString(stCfg.OrigNumber),
|
||||
TermNumber: cdr.FieldsAsString(stCfg.TermNumber),
|
||||
BillToNumber: cdr.FieldsAsString(stCfg.BillToNumber),
|
||||
Zipcode: cdr.FieldsAsString(stCfg.Zipcode),
|
||||
Plus4: cdr.FieldsAsString(stCfg.Plus4),
|
||||
P2PZipcode: cdr.FieldsAsString(stCfg.P2PZipcode),
|
||||
P2PPlus4: cdr.FieldsAsString(stCfg.P2PPlus4),
|
||||
TransDate: aTimeLoc.Format("2006-01-02T15:04:05"),
|
||||
Revenue: revenue,
|
||||
Units: unts,
|
||||
UnitType: cdr.FieldsAsString(stCfg.UnitType),
|
||||
Seconds: int64(cdr.Usage.Seconds()),
|
||||
TaxIncludedCode: cdr.FieldsAsString(stCfg.TaxIncluded),
|
||||
TaxSitusRule: cdr.FieldsAsString(stCfg.TaxSitusRule),
|
||||
TransTypeCode: cdr.FieldsAsString(stCfg.TransTypeCode),
|
||||
SalesTypeCode: cdr.FieldsAsString(stCfg.SalesTypeCode),
|
||||
RegulatoryCode: stCfg.RegulatoryCode,
|
||||
TaxExemptionCodeList: taxExempt,
|
||||
},
|
||||
}
|
||||
return stReq, nil
|
||||
}
|
||||
|
||||
// SureTax Request type
|
||||
type SureTaxRequest struct {
|
||||
ClientNumber string // Client ID Number – provided by SureTax. Required. Max Len: 10
|
||||
BusinessUnit string // Client’s Business Unit. Value for this field is not required. Max Len: 20
|
||||
ValidationKey string // Validation Key provided by SureTax. Required for client access to API function. Max Len: 36
|
||||
DataYear string // Required. YYYY – Year to use for tax calculation purposes
|
||||
DataMonth string // Required. MM – Month to use for tax calculation purposes. Leading zero is preferred.
|
||||
TotalRevenue float64 // Required. Format: $$$$$$$$$.CCCC. For Negative charges, the first position should have a minus ‘-‘ indicator.
|
||||
ReturnFileCode string // Required. 0 – Default.Q – Quote purposes – taxes are computed and returned in the response message for generating quotes.
|
||||
ClientTracking string // Field for client transaction tracking. This value will be provided in the response data. Value for this field is not required, but preferred. Max Len: 100
|
||||
IndustryExemption string // Reserved for future use.
|
||||
ResponseGroup string // Required. Determines how taxes are grouped for the response.
|
||||
ResponseType string // Required. Determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response.
|
||||
ItemList []*STRequestItem // List of Item records
|
||||
}
|
||||
|
||||
// Part of SureTax Request
|
||||
type STRequestItem struct {
|
||||
LineNumber string // Used to identify an item within the request. If no value is provided, requests are numbered sequentially. Max Len: 40
|
||||
@@ -52,62 +127,6 @@ type STRequestItem struct {
|
||||
TaxExemptionCodeList []string // Required. Tax Exemption to be applied to this item only.
|
||||
}
|
||||
|
||||
// Init a new request to be sent out to SureTax
|
||||
func NewSureTaxRequest(clientNumber, validationKey string, timezone *time.Location, originationNrTpl, terminationNrTpl utils.RSRFields, cdr *StoredCdr) (*SureTaxRequest, error) {
|
||||
if clientNumber == "" {
|
||||
return nil, utils.NewErrMandatoryIeMissing("ClientNumber")
|
||||
}
|
||||
if validationKey == "" {
|
||||
return nil, utils.NewErrMandatoryIeMissing("ValidationKey")
|
||||
}
|
||||
aTime := cdr.AnswerTime.In(timezone)
|
||||
stReq := &SureTaxRequest{ClientNumber: clientNumber,
|
||||
ValidationKey: validationKey,
|
||||
DataYear: strconv.Itoa(aTime.Year()),
|
||||
DataMonth: strconv.Itoa(int(aTime.Month())),
|
||||
TotalRevenue: utils.Round(cdr.Cost, 4, utils.ROUNDING_MIDDLE),
|
||||
ReturnFileCode: "0",
|
||||
ClientTracking: cdr.CgrId,
|
||||
ResponseGroup: "03",
|
||||
ResponseType: "",
|
||||
ItemList: []*STRequestItem{
|
||||
&STRequestItem{
|
||||
OrigNumber: cdr.FieldsAsString(originationNrTpl),
|
||||
TermNumber: cdr.FieldsAsString(terminationNrTpl),
|
||||
BillToNumber: cdr.FieldsAsString(originationNrTpl),
|
||||
TransDate: aTime.Format("2006-01-02T15:04:05"),
|
||||
Revenue: utils.Round(cdr.Cost, 4, utils.ROUNDING_MIDDLE),
|
||||
Units: 1,
|
||||
UnitType: "00",
|
||||
Seconds: int64(utils.Round(cdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE)),
|
||||
TaxIncludedCode: "0",
|
||||
TaxSitusRule: "1",
|
||||
TransTypeCode: "010101",
|
||||
SalesTypeCode: "R",
|
||||
RegulatoryCode: "01",
|
||||
TaxExemptionCodeList: []string{"00"},
|
||||
},
|
||||
},
|
||||
}
|
||||
return stReq, nil
|
||||
}
|
||||
|
||||
// SureTax Request type
|
||||
type SureTaxRequest struct {
|
||||
ClientNumber string // Client ID Number – provided by SureTax. Required. Max Len: 10
|
||||
BusinessUnit string // Client’s Business Unit. Value for this field is not required. Max Len: 20
|
||||
ValidationKey string // Validation Key provided by SureTax. Required for client access to API function. Max Len: 36
|
||||
DataYear string // Required. YYYY – Year to use for tax calculation purposes
|
||||
DataMonth string // Required. MM – Month to use for tax calculation purposes. Leading zero is preferred.
|
||||
TotalRevenue float64 // Required. Format: $$$$$$$$$.CCCC. For Negative charges, the first position should have a minus ‘-‘ indicator.
|
||||
ReturnFileCode string // Required. 0 – Default.Q – Quote purposes – taxes are computed and returned in the response message for generating quotes.
|
||||
ClientTracking string // Field for client transaction tracking. This value will be provided in the response data. Value for this field is not required, but preferred. Max Len: 100
|
||||
IndustryExemption string // Reserved for future use.
|
||||
ResponseGroup string // Required. Determines how taxes are grouped for the response.
|
||||
ResponseType string // Required. Determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response.
|
||||
ItemList []*STRequestItem // List of Item records
|
||||
}
|
||||
|
||||
// Converts the request into the format SureTax expects
|
||||
func (self *SureTaxRequest) AsHttpForm() (url.Values, error) {
|
||||
jsnContent, err := json.Marshal(self)
|
||||
@@ -122,7 +141,7 @@ func (self *SureTaxRequest) AsHttpForm() (url.Values, error) {
|
||||
// SureTax Response type
|
||||
type SureTaxResponse struct {
|
||||
Successful string // Response will be either ‘Y' or ‘N' : Y = Success / Success with Item error N = Failure
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
@@ -152,3 +171,53 @@ type STTaxItem struct {
|
||||
TaxTypeDesc string // Tax Type Description
|
||||
TaxAmount float64 // Tax Amount
|
||||
}
|
||||
|
||||
func SureTaxProcessCdr(cdr *StoredCdr) error {
|
||||
stCfg := config.CgrConfig().SureTaxCfg()
|
||||
if stCfg == nil {
|
||||
return errors.New("SureTax configuration missing")
|
||||
}
|
||||
if sureTaxClient == nil { // First time used, init the client here
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: config.CgrConfig().HttpSkipTlsVerify},
|
||||
}
|
||||
sureTaxClient = &http.Client{Transport: tr}
|
||||
}
|
||||
req, err := NewSureTaxRequest(cdr, stCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := sureTaxClient.Post(stCfg.Url, "application/json", bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode > 299 {
|
||||
return fmt.Errorf("Unexpected status code received: %d", resp.StatusCode)
|
||||
}
|
||||
var stResp SureTaxResponse
|
||||
if err := json.Unmarshal(respBody, &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
|
||||
if !stCfg.IncludeLocalCost {
|
||||
cdr.Cost = utils.Round(stResp.TotalTax, config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
} else {
|
||||
cdr.Cost = utils.Round(cdr.Cost+stResp.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)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,47 +28,48 @@ import (
|
||||
)
|
||||
|
||||
func TestNewSureTaxRequest(t *testing.T) {
|
||||
storedCdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
|
||||
cgrId := utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String())
|
||||
cdr := &StoredCdr{CgrId: cgrId, 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", Supplier: "SUPPL1",
|
||||
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(12) * time.Second, Pdd: time.Duration(7) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans", Rated: true,
|
||||
}
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
cfg.SureTaxCfg.ClientNumber = "000000000"
|
||||
cfg.SureTaxCfg.ValidationKey = "19491161-F004-4F44-BDB3-E976D6739A64"
|
||||
cfg.SureTaxCfg.Timezone = time.UTC
|
||||
stCfg := cfg.SureTaxCfg()
|
||||
stCfg.ClientNumber = "000000000"
|
||||
stCfg.ValidationKey = "19491161-F004-4F44-BDB3-E976D6739A64"
|
||||
stCfg.Timezone = time.UTC
|
||||
eSureTaxRequest := &SureTaxRequest{
|
||||
ClientNumber: cfg.SureTaxCfg.ClientNumber,
|
||||
ValidationKey: cfg.SureTaxCfg.ValidationKey,
|
||||
ClientNumber: "000000000",
|
||||
ValidationKey: "19491161-F004-4F44-BDB3-E976D6739A64",
|
||||
DataYear: "2013",
|
||||
DataMonth: "11",
|
||||
TotalRevenue: 1.01,
|
||||
ReturnFileCode: "0",
|
||||
ClientTracking: storedCdr.CgrId,
|
||||
ClientTracking: cgrId,
|
||||
ResponseGroup: "03",
|
||||
ResponseType: "",
|
||||
ResponseType: "D4",
|
||||
ItemList: []*STRequestItem{
|
||||
&STRequestItem{
|
||||
OrigNumber: "1001",
|
||||
TermNumber: "1002",
|
||||
BillToNumber: "1001",
|
||||
BillToNumber: "",
|
||||
TransDate: "2013-11-07T08:42:26",
|
||||
Revenue: 1.01,
|
||||
Units: 1,
|
||||
UnitType: "00",
|
||||
Seconds: 12,
|
||||
TaxIncludedCode: "0",
|
||||
TaxSitusRule: "1",
|
||||
TaxSitusRule: "04",
|
||||
TransTypeCode: "010101",
|
||||
SalesTypeCode: "R",
|
||||
RegulatoryCode: "01",
|
||||
TaxExemptionCodeList: []string{"00"},
|
||||
RegulatoryCode: "03",
|
||||
TaxExemptionCodeList: []string{},
|
||||
},
|
||||
},
|
||||
}
|
||||
if stReq, err := NewSureTaxRequest(cfg.SureTaxCfg.ClientNumber, cfg.SureTaxCfg.ValidationKey, cfg.SureTaxCfg.Timezone, cfg.SureTaxCfg.OriginationNumber,
|
||||
cfg.SureTaxCfg.TerminationNumber, storedCdr); err != nil {
|
||||
if stReq, err := NewSureTaxRequest(cdr, stCfg); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSureTaxRequest, stReq) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSureTaxRequest.ItemList[0], stReq.ItemList[0])
|
||||
|
||||
@@ -235,6 +235,8 @@ const (
|
||||
NOT_AVAILABLE = "N/A"
|
||||
CALL = "call"
|
||||
EXTRA_FIELDS = "ExtraFields"
|
||||
META_SURETAX = "*sure_tax"
|
||||
SURETAX = "suretax"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
Reference in New Issue
Block a user