Passing Billing ID to Asterisk Database

Hi there,
in my business, we receive calls on behalf of clients and we quite often have to transfer calls to clients or make calls on behalf of clients. We are looking at adding two new fields to the asterisk database, these being ‘direction’, which would be ‘inbound’ for inbound calls and ‘outbound’ for outbound calls and the second would be ‘billing_id’ which would be the billing id for each call.

For inbound calls:
I am thinking of getting the billing id from either:

  • Setting the “CID Name Prefix” on the General Tab with the billing ID or
  • CID Look up source or
  • by creating a custom field for Inbound Routes and adding the Billing ID there
    Any thoughts on this and how to add a custom fields

For Outbound Calls:
is there a way of adding the billingi_d to the number dialled either by prepending or appending a string that will get recognised by FreePbx, will write to the DBase and then get stripped out /dropped when the call is placed
Example, if I am calling 61416999999 and the billing id is 195, if I dial 61416999999*195 can the *195 be recognised, removed and 195 placed into the billing_id field of the outbound call?

Any feedback or help with this would be greatly appreciated

Thanks

Frank

That shouldn’t be necessary; the CDRs have Userfield and Account fields that are unpopulated by default and available to the user.

For incoming calls, do you have a separate DID per client, do they forward to a common DID but are distinguished by a Diversion header, or some combination?

For outgoing calls, do you presently have a way to send the client’s number as caller ID when calling on their behalf? If not, will this upgrade include that capability?

On calls transferred to clients, do you send the original caller’s number, the client’s main number or your number as caller ID?

Tools that may be useful for this upgrade include
https://wiki.freepbx.org/display/FPG/Pin+Sets-Admin+Guide
https://wiki.freepbx.org/display/FPG/PINSet+Pro-Admin+Guide
https://www.voipsupport.it/wiki/index.php?title=Dynamic_Routes_Reference_documentation

That’s possible, but would require custom dial plan code. Assuming that your example represents an Australia mobile number and your system is set up to dial all numbers starting with the country code (but without the +), then you might instead use 019561416999999 (simpler custom code) or PIN Sets (no custom code but is not friendly to contact lists, redial, etc.)

Once we know the present and desired behavior, we can likely provide better advice.

I did something similar a couple years ago for a customer I’ll try and remember to dig out that code and post it tomorrow

1 Like

So here is what I did.

First, they had an existing MySQL database with a list of 5 digit codes and CID numbers to use with them.

So I added func_obdc.conf to connect to that database and run a query based on the autcode (authorization code) that the user dialed.

cat /etc/asterisk/func_odbc.conf 
; Return the CID to use based on the AUTCODE dialed.
[AUTCODECID]
prefix=GET
dsn=jared-custom
readsql=SELECT cid_num FROM autcodes WHERE code = '${ARG1}'

; Return the ID of the autcode if it exists.
; This is used to validate the call can be placed.
[VALIDATEAUTCODE]
prefix=GET
dsn=jared-custom
readsql=SELECT id FROM autcodes WHERE code = '${ARG1}'

Then I setup outbound routes with pattern matches set appropriately.
They dial 7 or 8 depending on the office, then 11 digits then 5 digit code.

That outbound route has a custom trunk that simply terminates the call, as the next bit will move the call to a different route.

[macro-dialout-trunk-predial-hook]
exten => s,1,NoOp()
; Skip if this is an emergency call
exten => s,n,GotoIf($["${EMERGENCYROUTE}"=="YES"]?emergencyrouteused)
; Check if the call has already been validated to go out, and skip the rest of the processing
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="Call_Validated_to_go_Out"]?skipvalidation)
; Depending on the outbound route send the call to be validated
; International calling needs no autcode
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="International_Allowed"]?skipvalidation)
; International calling needs no autcode
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="Intl_Out"]?skipvalidation)
; NANPA Allowed to dial with no autcode
; Executive Conference room, etc.
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="NANPA_Allowed_No_Code"]?skipvalidation)
; NANPA dialed with a code
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="NANPA_Dialed_with_Code"]?validatenanpawithautcode,s,1)
; NANPA dialed without a code
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="NANPA_Dialed_no_Code"]?validatenanpanoautcode,s,1)
;More logic coming. For now, dump channel and terminate call.
exten => s,n,DumpChan
exten => s,n,Hangup()
; The call was an emegerncy dial, do no processing, but note the log.
exten => s,n(emergencyrouteused),NoOp()
exten => s,n,Log(NOTICE, 911 was dialed by extension ${FROMEXTEN})
; The call was validated, nothing else to do.
exten => s,n(skipvalidation),NoOp()

The above will send a call dialed with a code to this routine, that get the CID to use based on the code used.

[validatenanpawithautcode]
exten => s,1,NoOp()
; NANPA format means digit zero is 7 or 8 and digit one is a 1 
; digits two through ten should be a 10 digit number
; the last five digits are the AUTCODE
exten => s,n,Set(USERDIALED=${OUTNUM:2:10})
exten => s,n,Set(AUTCODE=${OUTNUM:-5})
; Go check for a valid code
exten => s,n,Set(RETURNTOCONTEXT=validatenanpawithautcode)
exten => s,n,GoTo(checkvalidautcode,s,1)
; Return location if AUTCODE is valid
exten => s,n(autcodevalid),NoOp()
; Check if the AUTCODE has a CID associated with it. 
exten => s,n,Set(AUTCODECIDNUM=${GET_AUTCODECID(${AUTCODE})})
; If there is no CID jump to autcidno, otherwise autcidyes
exten => s,n,GotoIf($["${AUTCODECIDNUM}" == ""]?autcidno:autcidyes)
exten => s,n,Hangup()
exten => s,n(autcidyes),NoOp()
exten => s,n,Log(NOTICE, The AUTCODE of ${AUTCODE} has an associated CID of ${AUTCODECIDNUM}. Forcing it to apply.)
exten => s,n,Set(TRUNKCIDOVERRIDE=${AUTCODECIDNUM})
exten => s,n(autcidno),NoOp()
exten => s,n,DumpChan
; Go back to outbound route logic with the "secret" prefix of 8675309 (Jenny) that will match the pattern to get to an outboud trunk
exten => s,n,Goto(outbound-allroutes,8675309${USERDIALED},1)
exten => s,n,Hangup()

That code will send it to this bit of logic to validate the code prior to getting the CID.

; This context checks that the AUTCODE value (last five digits) exists in the `autcodes` table
; See func_odbc.conf for the SQL statement.
; This context requires that the variable RETURNTOCONTEXT be set in by the context that calls it
; This context also requres that the calling context have a line labeled autcodevalid to return to
[checkvalidautcode]
exten => s,1,NoOp()
; Start a rety counter.
exten => s,n,Set(RETRYCODE=0)
; If code is invalid, user is prompted to try again and the call is sent back to here
exten => s,n(tryagain),NoOp()
; Check the database for the autcode. SQL query returns the `id` of the row if found
exten => s,n,Set(AUTCODEID=${GET_VALIDATEAUTCODE(${AUTCODE})})
; if no rows are returned jump to badaut, if something is returned jump to goodaut
exten => s,n,GotoIf($[${ODBCROWS} = 0]?badaut,1:goodaut,1)
exten => s,n,Hangup()
exten => badaut,1,NoOp()
exten => badaut,n(notfound),Log(NOTICE, The AUTCODE of ${AUTCODE} was not found, user needs to try again)
; Increment the fail counter
exten => badaut,n,Set(RETRYCODE=$[${RETRYCODE} + 1])
; If the user has failed 3 times (or more somehow) jump to toomanytries
exten => badaut,n,GotoIf($[${RETRYCODE} >= 3]?toomanytries,1)
; Tell them the code was bad and to try again
exten => badaut,n,Playback(you-entered)
exten => badaut,n,Playback(access-code)
exten => badaut,n,SayDigits(${AUTCODE})
exten => badaut,n,Playback(vm-pls-try-again)
exten => badaut,n,Set(TIMEOUT(response)=10)
exten => badaut,n,Read(AUTCODE,access-code,5,,2,5)
; If the entered code was 5 digits jump back up to try again, otherwise jump up to not found
exten => badaut,n,GotoIf($[${LEN(${AUTCODE})}==5]?s,tryagain:notfound)
exten => badaut,n,Hangup()
exten => goodaut,1,NoOp()
exten => goodaut,n,Log(NOTICE, The AUTCODE of ${AUTCODE} was found, let call proceed)
; The code was found, so go back to the context that we came from at the spot marked autcodevalid
exten => goodaut,n,GoTo(${RETURNTOCONTEXT},s,autcodevalid)
exten => goodaut,n,Hangup()
exten => toomanytries,1,NoOp()
exten => toomanytries,n,Log(NOTICE, The user failed to enter a valid AUTCODE too many times)
; The user the dialed the code wrong too many times, hangup the call
exten => toomanytries,n,Playback(sorry)
exten => toomanytries,n,Playback(goodbye)
exten => toomanytries,n,Hangup()

Assuming it validated and returned a CID, the dialed number, minus the code is prefixed with Jenny’s number 8675309 and sent back to the main outbound route functionality. Which now matches this outbound route that has a normal trunk referenced.

That does hit the above macro again, since it is an outbound hook. That is why it has a match for this route name to skip any more validation.

; Check if the call has already been validated to go out, and skip the rest of the processing
exten => s,n,GotoIf($["${OUTBOUND_ROUTE_NAME}"=="Call_Validated_to_go_Out"]?skipvalidation)

Feel free to rip this apart. What you want to do is not this complicated, but this should give you an idea of how flexible you can get with dial plan.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.