Support A2Billing :

provided by Star2Billing S.L.

Support A2Billing :
It is currently Sat Apr 20, 2024 12:19 am
Auto Dialer Software


All times are UTC




Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: Fri Jun 15, 2007 1:12 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Oh, the patch is for A2Billing 1.3.0 downloaded from the trunk with the latest modifications on the svn.

I can't find v1.2.3 (BrainCoral) anymore, where is it? I can just see Chameleon.

Without the right source code, I can't do much.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 18, 2007 2:41 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Here is an improved version of the patch.

If you have already applied the previous one, please apply it again. This will cause the patch command to detect that the patch has already been applied, and it will ask you the permission to revert the patch. The message should look like:

Code:
Reversed (or previously applied) patch detected!  Assume -R? [n] [color=red]y[/color]


Simply respond by pressing y and the Enter Key.

Then, you can go ahead and download and apply the following patch. This version takes care of connectcharge, disconnectcharge, and it uses the answeredtime value (time spent on the 1st leg while dialing the destination number).

To apply it, use the following commands:

# cd /var/lib/asterisk/agi-bin
# patch <a2billing.diff.txt

Now, I really need some help with the progressive rate. I have been looking at it for hour without finding a safe way of adapting it (massive continuous brain fart).


Attachments:
a2billing.diff.txt [8.78 KiB]
Downloaded 449 times
Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 5:51 am 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
Hi guys,

not sure whether u guys have already had a fix that cover all scenarios, i.e. CID callback, web callback, all callback, with flat as well as progressive rates.

I have a rather crude solution that will work for all. Tested it and seems fine. But, I may have overlooked something and it would be nice if you guys can give some comments on it.

FYI, I'm using a2billing v1.3.

There are 2 files affected: a2billing.php and Class.A2Billing.php. Changes are shown in bold.


------------------------------
a2billing.php
------------------------------


line 70:

Code:
$A2B = new A2Billing();
$A2B -> load_conf($agi, NULL, 0, $idconfig);

[b]$A2B -> mode = $mode;[/b]    // copied from asiby's patch.

$A2B -> debug( VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "IDCONFIG : $idconfig");



line 712:

Code:
if ($callback_mode == 'CID') {
    $charge_callback = 1;
    $A2B->agiconfig['use_dnid'] = 0;
    $A2B->agiconfig['number_try'] = 1;

    [b]$A2B->agiconfig['cid_enable'] = 0;[/b]

} elseif ($callback_mode == 'ALL') {
    $A2B->agiconfig['use_dnid'] = 0;
    $A2B->agiconfig['number_try'] = 1;

} else {
    $charge_callback = 1;
    // FOR THE WEB-CALLBACK
    $A2B->agiconfig['number_try'] = 1;
    $A2B->agiconfig['use_dnid'] = 1;
    $A2B->agiconfig['say_balance_after_auth'] = 0;
    $A2B->agiconfig['cid_enable'] = 0;
    $A2B->agiconfig['say_timetocall'] = 0;

}

[b]$A2B->callback_leg1_dest = $called_party;[/b]

$A2B -> debug( VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "[CALLBACK]:[GET VARIABLE : CALLED=$called_party | CALLING=$calling_party | MODE=$callback_mode | TARIFF=$callback_tariff | CBID=$callback_uniqueid | LEG=$callback_leg]");



------------------------------
Class.A2Billing.php
------------------------------


line 126:

Code:
var $hostname='';
var $currency='usd';

[b]var $mode = '';[/b]    // copied from asiby's patch.
[b]var $callback_leg1_dest = '';[/b]

var $timeout;
var $newdestination;



line 713:

Code:
// STRIP * FROM DESTINATION NUMBER
$this->destination = str_replace('*', '', $this->destination);

[b]if ($this->mode == 'callback') {
    $RateEngine_leg1 = new RateEngine();
    $resfindrate = $RateEngine_leg1->rate_engine_findrates($this, $this->callback_leg1_dest, $this->tariff);
    if ($resfindrate == 0) {
        $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "Something is wrong! - cannot find rate for leg1 [dest: $this->callback_leg1_dest]");
        return -1;
    }
}[/b]

// LOOKUP RATE : FIND A RATE FOR THIS DESTINATION



line 732:

Code:
/*$rate=$result[0][0];
if ($rate<=0) {
    //$prompt="prepaid-dest-blocked";
    $prompt="prepaid-dest-unreachable";
    continue;
}*/

[b]if ($this->mode == 'callback') {
    $epsilon = 1;
    for ($k = 0; $k < count($RateEngine->ratecard_obj); $k++) {
        $r = 0.5;
        $r_min = 0.0;
        $r_max = 1.0;
        $credit_leg1 = $r * $this->credit;
        $credit_leg2 = $this->credit - $credit_leg1;

        for (;;) {
            $timeout_leg1 = $RateEngine_leg1->rate_engine_calcultimeout($this, $credit_leg1) - 60;    // assuming 1 minute gone before leg2 is established.
            $timeout_leg2 = $RateEngine->rate_engine_calcultimeout($this, $credit_leg2, $k);

            if ($timeout_leg1 > $timeout_leg2) {
                $diff = $timeout_leg1 - $timeout_leg2;
                $r_max = $r;
                $r = ($r + $r_min) / 2;
            }
            else {
                $diff = $timeout_leg2 - $timeout_leg1;
                $r_min = $r;
                $r = ($r + $r_max) / 2;
            }

            if ($diff < $epsilon) {
                $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "CALCULTIMEOUT: k=$k - timeout=$timeout_leg2");
                break;
            }

            $credit_leg1 = $r * $this->credit;
            $credit_leg2 = $this->credit - $credit_leg1;
        }
    }
}
else {[/b]
    // CHECKING THE TIMEOUT
    $res_all_calcultimeout = $RateEngine->rate_engine_all_calcultimeout($this, $this->credit);

    $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "RES_ALL_CALCULTIMEOUT ::> $res_all_calcultimeout");
    if (!$res_all_calcultimeout) {
        $prompt="prepaid-no-enough-credit";
        $agi->stream_file($prompt, '#');
        return -1;
    }
[b]}[/b]

// calculate timeout
//$this->timeout = intval(($this->credit * 60 * 100) / $rate);




That's all. Comments?

regards,
-rs-

Added after 2 minutes:

LOL sorry... I've never posted anything before. I thought I can use BOLD and CODE together :-D

the changes are between and :-D

regards,
-rs-

Added after 1 minutes:

Man.. I'm really suck at this..

The changes is between [ b ] and [ /b ].

regards,
-rs-


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 4:17 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
lol, funny. I went throught the [ b ] thing also.

I found your code very interesting and the principle used is extremely simple. But I have noticed that you are using the actual tariff during the calculation of the 1st leg but I may be mistaking. If I am not, then the rates that are going to be used to calculate the timeout of the 1st leg will be the wrong one. Did you verify if the progressive rates will work with pin point accuracy? If so, that's might be it. I have just finished fine tuning and testing the flat rate and it has pin point accuracy.

I am just curious. You have used variables like $r, $r_min, and $r_max. What are they and how did you chose their values? I have my guesses, but I would like to here it from you.

Good job meessras

Added after 1 hours 53 minutes:

Additionally, I believe that your solution allows to have a situation where Leg A is using flat rate and Leg B using progressive rate and vice versa or both legs may be using either flat of progressive rate.

I will apply your changes to my installation with some modifications and get some results. My modifications will extract the appropriate rates of a leg at the right place and time.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 5:24 pm 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

Quote:
But I have noticed that you are using the actual tariff during the calculation of the 1st leg but I may be mistaking. If I am not, then the rates that are going to be used to calculate the timeout of the 1st leg will be the wrong one.


Hmm, I did use the actual tariff, but I don't see how it can be wrong because there's only one tariff used for both legs, which is the tariff of the card being used. Can u please enlighten me here? :D

Quote:
Did you verify if the progressive rates will work with pin point accuracy?


Sorry, I don't quite get what u mean by pin point accuracy. How do u measure the accuracy? My main aim is just to avoid negative balance :D

Quote:
I am just curious. You have used variables like $r, $r_min, and $r_max. What are they and how did you chose their values?


$r => proportion of credit that will be used to fund the first leg.
$r_min and $r_max => the lower and upper limit for me to do "binary search" to find the correct $r.

so, I started of by dividing the credit into 2 equal portions ($r = 0.5), half of the credit is to fund the first leg, and another half to fund the second leg.

If I find there's too much credit for the first leg, the next $r will be the mid-point between $r and $r_min, otherwise, the next $r will be the mid-point between $r and $r_max.
I keep on doing that until I find the right $r which gives equal amount of timeout for both legs.

regards,
-rs-


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 6:23 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Ok

My mistake about the tariff, I was thinking in another language :D.

The accuracy I was referring to is about the final result. Avoiding negative balance is good. But we also do not want the client or us to loose any penny. I will soon show you what I mean when I will post our version of the fix soon.

A bug that I had mentioned in another thread is another cause for the negative balance. And it needs to be fixed ASAP.

Here it is. The min_credit_2call should be dynamically generated from the rateinitial value of the destination instead of having its value set in a2billing.conf

The reason is simple. Let's assume the following:

- account balance: 3¢
- min_credit_2call=2¢
- Rate of the destination: rateinitial=5¢/min

It the current release, the system will call you back because your balance is higher than min_credit_2call, but you will not be able to reach any destination because of the low balance, and that's ok

On the other hand, you will consume at least 1 billing block. In this case, 5¢, and your balance will drop to -2¢.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 11:22 pm 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

that's a good point u mentioned there about the min_credit_2call. I have never thought of that. I'll be waiting for ur post.

regards,
-rs-


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 3:13 am 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
meessras,

The line identified in the code below has a special purpose, without it, even with a successful callerID identification, A2Billing ask for the pin code during the second phase of a cid-callback (if the option is activated in a2billing just in case).

Code:
if ($callback_mode=='CID'){ 
   $charge_callback = 1;
   $A2B->agiconfig['use_dnid'] = 0;
   $A2B->agiconfig['number_try'] =1;
   $A2B->CallerID = $called_party; //<<<<------- This line is not in your code
}elseif ($callback_mode=='ALL'){ 


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 3:32 am 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

I replaced that line with the following:
Code:
$A2B->agiconfig['cid_enable'] = 0;


So that during the second phase of the callback, authentication is done using the accountcode.

Why? because my setup is such:

registered caller ID => 91595790 (Singapore mobile number, without country code/area code).

in extensions.conf, I have:
Code:
[a2billing-cid-callback]
exten => s, 1, DeadAGI(a2billing.php|1|65);
exten => s, 2, Hangup


where 65 is Singapore country code.

Now, during the second phase of the callback, if I were to do authentication by callerid, and callerid = called_party, it will try to find card for callerid 6591595790 and find nothing.

regards,
-rs-


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 07, 2007 5:55 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
I think that you are calling the agi the wrong way.

This code ...

Code:
[a2billing-cid-callback]
exten => s, 1, DeadAGI(a2billing.php|1|65);
exten => s, 2, Hangup


Must be replaced with ...

Code:
[a2billing-cid-callback]
exten => s, 1, DeadAGI(a2billing.php|1||65);
exten => s, 2, Hangup


If you don't use a parameter somewhere in the middle of other parameters, you must keep the parameters order otherwise a2billing.php with thing that 65 is the 3rd parameter which has the following possible values: callback, all-callback, voucher, cid-callback, ...

By not using the "callback mode" parameter (the 3rd) the a2billing will choose the default one.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 08, 2007 4:09 am 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

sorry, that was a typo. I did put 'cid-callback' as the third param and '65' as the last param.

I think the problem is with the [a2billing-callback] context. Ok, to give u the whole picture, this is what I have in extensions.conf:

Code:
[a2billing-callback]
exten => _X., 1, DeadAGI(a2billing.php|1|callback)
exten => _X., 2, Hangup

[a2billing-cid-callback]
exten => s, 1, DeadAGI(a2billing.php|1|cid-callback|65)
exten => s, 2, Hangup


And now, during the second phase of the callback, [a2billing-callback] will be used, and here, I don't have '65' prefix specified. I did not put '65' in [a2billing-callback] because that context is also used for web-callback, and I don't want to append '65' for web-callback.

I think if I have separate context for web-callback, say [a2billing-web-callback] and add '65' in [a2billing-callback], that should be ok. Let me try that out.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 11, 2007 5:13 am 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

There was a very serious bug in the code that I posted earlier that causes the loop to go on forever. The problem was with the condition that I used to check whether to terminate the loop, which was the epsilon thingy.

I have a better version that solves that bug and much more accurate. Just like ur patch, it takes into account the answered time of the first leg up to the point, where we're going to compute the timeout for the second leg.

Here's the code: (I'll just post the part where I made changes)

Class.A2Billing.php - line 725

Code:
// IF DONT FIND RATE
if ($resfindrate==0) {
    $prompt="prepaid-dest-unreachable";
    $agi->stream_file($prompt, '#');
    return -1;
}

/*$rate=$result[0][0];
if ($rate<=0) {
    //$prompt="prepaid-dest-blocked";
    $prompt="prepaid-dest-unreachable";
    continue;
}

if ($this->mode == 'callback') {
    // determine leg1 answered time up to this point.
    global $G_startime;
    $answeredtime_leg1 = time() - $G_startime;
    $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "LEG1 ANSWERED TIME SO FAR = $answeredtime_leg1");

    // compute the cost of leg1 up to this point.
    $freetimetocall_package_offer = $RateEngine_leg1->ratecard_obj[0][45];
    $freetimetocall = $RateEngine_leg1->ratecard_obj[0][46];
    if (!is_numeric($freetimetocall)) { $freetimetocall = 0; }
    $freetimetocall_left = $RateEngine_leg1->freetimetocall_left[0];
    if (!is_numeric($freetimetocall_left)) { $freetimetocall_left = 0; }
    $freetimetocall_used = 0;
    if (($freetimetocall_package_offer == 1) && ($freetimetocall > 0) && ($freetimetocall_left > 0)) {
        if ($freetimetocall_left >= $answeredtime_leg1) {
            $freetimetocall_used = $answeredtime_leg1;
        }
        else {
            $freetimetocall_used = $freetimetocall_left;
        }
    }
    $RateEngine_leg1->usedratecard = 0;
    $RateEngine_leg1->rate_engine_calculcost($this, $answeredtime_leg1, 0, $freetimetocall_used);
    $cost_leg1 = $RateEngine_leg1->lastcost;
    $credit = $this->credit + $cost_leg1;
    $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "ACTUAL CREDIT = $this->credit; LEG1 COST SO FAR = $cost_leg1; EFFECTIVE CREDIT = $credit");

    // compute the timeout for leg2.
    for ($k = 0; $k < count($RateEngine->ratecard_obj); $k++) {
        $r = 0.5;
        $r_min = 0.0;
        $r_max = 1.0;
        $credit_leg1 = $r * $credit;
        $credit_leg2 = $credit - $credit_leg1;
        $timeout_leg1_old = 0;
        $timeout_leg2_old = 0;

        for (;;) {
            $timeout_leg1 = $RateEngine_leg1->rate_engine_calcultimeout($this, $credit_leg1);
            $timeout_leg2 = $RateEngine->rate_engine_calcultimeout($this, $credit_leg2, $k);

            if ((substr($timeout_leg1, 0, 5) == 'ERROR') || substr($timeout_leg2, 0, 5) == 'ERROR')) {
                $prompt = "prepaid-no-enough-credit";
                $agi->stream_file($prompt, '#');
                return -1;
            }

            if ($timeout_leg1 > $timeout_leg2) {
                $r_max = $r;
                $r = ($r + $r_min) / 2;
            }
            else {
                $r_min = $r;
                $r = ($r + $r_max) / 2;
            }

            // if timeouts computed are the same as previous iteration, break out!
            if (($timeout_leg1 == $timeout_leg1_old) && ($timeout_leg2 == $timeout_leg2_old)) {
                $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "CALCULTIMEOUT: k=$k - timeout=$timeout_leg2");
                break;
            }

            $credit_leg1 = $r * $credit;
            $credit_leg2 = $credit - $credit_leg1;
            $timeout_leg1_old = $timeout_leg1;
            $timeout_leg2_old = $timeout_leg2;
        }
    }
}
else {
    // CHECKING THE TIMEOUT
    $res_all_calcultimeout = $RateEngine->rate_engine_all_calcultimeout($this, $this->credit);

    $this->debug(VERBOSE | WRITELOG, $agi, __FILE__, __LINE__, "RES_ALL_CALCULTIMEOUT ::> $res_all_calcultimeout");
    if (!$res_all_calcultimeout) {
        $prompt="prepaid-no-enough-credit";
        $agi->stream_file($prompt, '#');
        return -1;
    }
}


Comments?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 7:15 pm 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Excellent work.

Can you post a patch created with the svn diff tools? It will make the update easier. In the mean time, I had promised that I was going to post what I had done so far. But I changed my mind because I had discovered some imperfections in the code. My new approach is summarized in the attached ms-excel document. Basically, I just dynamically combine both rates together, and after that process, I end up with a global rate that include the rates of both legs and from there we calculate the timeout. And the process of fusing the rates together works whether we have FLAT-FLAT, FLAT-PROGRESSIVE or PROGESSIVE-PROGRESSIVE rates.

I will test your code, and use it instead if it works as you said.

Added after 3 minutes:

By the way, I am almost done with the PHP coding of what you will see in the excel document.


Attachments:
Timeout Estimator.zip [92.18 KiB]
Downloaded 450 times
Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 13, 2007 2:34 am 
Offline

Joined: Mon Jul 02, 2007 4:54 am
Posts: 9
asiby,

I noticed there're still a couple of things not quite right (maybe more :-D):

    The "RINGING" time of the second leg was not taken into consideration when calculating the timeout. As a result, credit for prepaid user can still go negative. If the billing block is big (e.g 60 seconds) then this problem may not appear.

    The patch is still not 100% correct when there's package offer. The free time to call should be distributed equally among both legs when computing the timeout.


I'm still fixing the second issue. As for the first one, currently I don't know how to solve that. The best I can think of now, is to reserve say 30 seconds (assuming u put 30 seconds dial timeout) worth of credit before computing the timeout. But, this means that the client loses out some money. Unless, there's a way to set the call timeout once the call is answered. Is there?

I'll post the diff soon.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 13, 2007 8:28 am 
Offline
User avatar

Joined: Mon Apr 30, 2007 6:43 am
Posts: 1060
Location: Canada
Here is a way to get the exact value of the time spent on the first leg while the 2nd leg is still not connected.

First of all, notice a variable called $G_startime that is initialized not far from the beginning of a2billing.php like this.

Code:
$G_startime = time();


You can access the value of this variable as global variable like this:

Code:
global $G_startime;


Then, anytime you want to know what time has been spent, just do this:

Code:
$answeretime = time() - $G_startime;


Another thing, since we are dealing with classes and different scopes, it may be wise to use global $G_startime; at every level of the function hierarchy that lead to the one you are working on. I have notice that in some situations, the "global" statement only allow to access whatever variable is in the parent scope. But in the case of $G_startime, we need to climb up to the root level.

I hope that this will help. I am still working on my solution. And by the way, I believe that once my rates will be fused together, they will both use the freetime_2call at the same time, as well as the package offers, and so on. I will speed up my work and hopefully, it should be complete soon.

Regards


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3  Next
Hosted Voice Broadcast


All times are UTC


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group