Logo Search packages:      
Sourcecode: netams version File versions  Download package

billing.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: billing.c,v 1.127 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

unsigned max_accounts_number=0;

FeeCounters FC;

//////////////////////////////////////////////////////////////////////////
SubPlan::SubPlan(oid newid): Object() {
      id=newid;
      fee=0;
      spread='M';
      inc_in=inc_out=0L;
      flags=SPLAN_NONE;
      pid=0;
      pay_in=pay_out=0;
      overdraft_in=overdraft_out=0;
      connected_plans=0;
      inc_adjust=0; 
      fee_adjust=1; 
}
//////////////////////////////////////////////////////////////////////////
Plan::Plan(oid newid): Object() {
      id=newid;
      name=description=NULL;
      root=NULL; 
      connected_accounts=0;
      num_subplans=0;
}

Plan::~Plan() {
      bSPlist *bsp;
      while(root) {
            bsp=root;
            root=root->next;
            aFree(bsp);
      }
      if(name) aFree(name);
      if(description) aFree(description);
}

u_char Plan::AddSubPlan(SubPlan *sp, u_char flag) {
      bSPlist *bsp=NULL,*p=NULL;

      for(bsp=root;bsp!=NULL; bsp=bsp->next) {
            if(bsp->sp==sp) break;
            p=bsp;
      }

      if(flag==ADD) { //ADD
            if(bsp) return 0;
            bsp=(bSPlist*)aMalloc(sizeof(bSPlist));
            if(root==NULL) root=bsp;
            else p->next=bsp;
            bsp->sp=sp;
            bsp->next=NULL;
            num_subplans++;
            sp->connected_plans++;
      } else { //REMOVE
            if(!bsp) return 0;
            if(root==bsp) root=root->next;
            else p->next=bsp->next;
            aFree(bsp);
            num_subplans--;
            sp->connected_plans--;
      }
      return 1;
}

void Plan::SetAccountData(Account *ac) {
      SubPlan *sp;
      u_char poz=0;
      billing_data *bd;
      
      aDebug(DEBUG_BILLING, "Set BDATAS for %s (%06X)\n", ac->name, ac->id);

      ac->status|=ACCOUNT_BDATA_NEED_SYNC;

      if(num_subplans) ac->data=(billing_data*)aMalloc(num_subplans*sizeof(billing_data));

      for(bSPlist *bsp=root; bsp!=NULL; bsp=bsp->next, poz++) {
            sp=bsp->sp;

            //clear and prepare
            bzero(&ac->data[poz], sizeof(billing_data));
            
            bd=&ac->data[poz];
            
            bd->h.from=bd->d.from=bd->w.from=bd->m.from=FC.mt;

            if(!(sp->flags&SPLAN_UNLIM_IN) && sp->inc_in) {
                  bd->m.in = -(long long)sp->inc_in;
                  if (sp->inc_adjust) { //adjust IN bstats accroding time
                        long long tmp = (long long)((double)sp->inc_in*FC.traf_mult);
                        aDebug(DEBUG_BILLING, "Adjusting IN bstats for %s (%06X) from %lld to %lld\n", \
                              name, id, -bd->m.in, tmp);
                        bd->m.in = -tmp;
                  }
                  bd->flags|=BDATA_NEED_SYNC;
            }
            if(!(sp->flags&SPLAN_UNLIM_OUT) && sp->inc_out) {
                  bd->m.out = -(long long)sp->inc_out;
                  if (sp->inc_adjust) { //adjust OUT bstats accroding time
                        long long tmp=(long long)((double)sp->inc_out*FC.traf_mult);
                        aDebug(DEBUG_BILLING, "Adjusting OUT bstats for %s (%06X) from %lld to %lld\n", \
                              name, id, -bd->m.out, tmp);
                        bd->m.out = -tmp;
                  }
                  bd->flags|=BDATA_NEED_SYNC;
            }
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
AccountsList::AccountsList(): List() {
      max_accounts_number_set=max_accounts_number;
      last_update=0;
}

Account* AccountsList::Get(char *param){
      Account *t=NULL;
      
      oid id=strtol(param, NULL, 16);
      t=(Account*)getById(id);
      if(t) return t;

      netams_rwlock_rdlock(&rwlock);
      for (t=(Account*)root; t!=NULL; t=(Account*)t->next)
            if (STREQ(t->name,param)) break;
      netams_rwlock_unlock(&rwlock);

      return t;
}

void AccountsList::UpdateAccounts() {
      FeeCounters *fc=PrepareFeeCounters();
      time_t hour_change_t    = fc->ht;
      time_t month_change_t   = fc->mt;
      
      if(hour_change_t <= last_update) return;
      
      billing_data *bd;

      netams_rwlock_rdlock(&rwlock);
      for(Account *ac=(Account*)root; ac!=NULL; ac=(Account*)ac->next) {
            u_char poz=0;
            for (bSPlist *spl=ac->plan?ac->plan->root:NULL; spl!=NULL; spl=spl->next, poz++){
                  bd=&ac->data[poz];
                  
                  //update periodic counters
                  if(bd->h.from!=fc->ht) {
                        bd->h.in=bd->h.out=0;
                        bd->h.from=fc->ht;
                        if(bd->d.from!=fc->dt){
                              bd->d.in=bd->d.out=0;
                              bd->d.from=fc->dt;
                              if(bd->w.from!=fc->wt){
                                    bd->w.in=bd->w.out=0;
                                    bd->w.from=fc->wt;
                              }
                        }
                  }
            }

            if(month_change_t > ac->blocked && (ac->status&ACCOUNT_BEBLOCKED)) {
                  aDebug(DEBUG_BILLING, "activate pending blocks for account %s(%06X)\n",ac->name,ac->id);
                  ac->UpdateStatus(AC_BLOCK, month_change_t);
            }
            //look into Update() - if nextplan==plan - we only update counters
            if(month_change_t > ac->nextplan_ch) {
                  if (ac->nextplan_ch!=0) {
                        LogEvent(BILLING, 0, 0, ac->id, "balance NOW %lf", ac->balance);
                  }
                  ac->Update(ac->nextplan);
            }
            
            //Charge Fee
            ac->ChargeFee();
      }
      last_update=hour_change_t;
      netams_rwlock_unlock(&rwlock);
}

void AccountsList::RestoreAccounts() {
//    time_t month_t=FC.mt;
//    time_t now=FC.now;
//    time_t changed;

      netams_rwlock_rdlock(&rwlock);
      for(Account *ac=(Account*)root; ac!=NULL; ac=(Account*)ac->next) {
            if(ac->plan) ac->plan->SetAccountData(ac);

            ac->status&=~ACCOUNT_NEED_SYNC;
            ac->status&=~ACCOUNT_BDATA_NEED_SYNC;
      }
      netams_rwlock_unlock(&rwlock);
}
//////////////////////////////////////////////////////////////////////////////////////////
Account::Account(){
      time_t t=time(NULL);  

      id=0;
      balance=0; 
      credit_limit=0;
      blocked=t; created=t; changed=t; 
      status=ACCOUNT_BLOCKED|ACCOUNT_DENIED; //set initial status
      description=NULL;
      num_units=0;
      email=password=NULL; 
      plan=nextplan=NULL; 
      last_fee_ch=nextplan_ch=plan_ch=0;
      bUroot=NULL;
      data=NULL;
      name=NULL;
}

Account::~Account() {
      if(name) aFree(name);
      if(description) aFree(description);
      if(email) aFree(email);
      if(password) aFree(password);
      if(data) aFree(data);
      
      bUlist *bu;
      while(bUroot) {
            bu=bUroot;
            bUroot=bUroot->next;
            SetUnitAccountPolicy(bu->u, REMOVE);
            bu->u->account=NULL;
            aFree(bu);
      }
}

void Account::setName(char *name_t) {
      if (name) aFree(name);
      name=set_string(name_t);
}

void Account::Update(Plan *pl) {
      time_t change_t=FC.mt;

      if(plan!=pl) {
            LogEvent(BILLING, 0, 0, id, "Plan changed from %s(%u) to %s(%u)\n", plan?plan->name:"-", plan?plan->id:0, pl?pl->name:"-", pl?pl->id:0);
            aDebug(DEBUG_BILLING, "Plan for account %s(%06X) changing from %s(%u) to %s(%u)\n", name, id, plan?plan->name:"<\?\?>", plan?plan->id:0, pl?pl->name:"<\?\?>", pl?pl->id:0);

            //update counters and references    
            if(plan) plan->connected_accounts--;
            plan=pl;
            
            nextplan=plan;
      
            if(data) { 
                  aFree(data);
                  data=NULL;
            }
            
            if(plan) plan->connected_accounts++;

            //update units policies
            for(bUlist *bu=bUroot;bu!=NULL; bu=bu->next) {
                  SetUnitAccountPolicy(bu->u, ADD);
            }
            plan_ch=change_t;
      }
      
      if(plan) plan->SetAccountData(this);

      status|=ACCOUNT_NEED_SYNC;
      //we need to update nextplan_ch to proper check month change 
      nextplan_ch=change_t;
}

void Account::SetUnitAccountPolicy(NetUnit *u, u_char flag) {
      if(u->ap) {
            delete u->ap;
            u->ap=NULL;
      }
      if(flag==REMOVE) {
            u->flags &= ~NETUNIT_BROKEN_ACCT_MF;
            return;
      }
      Policy *p;
      policy_data *pd;
      bSPlist *bsp;

      if(!plan) return; //no need to allocate
      u->ap=new PdList();
      char *s = NULL;
      print_to_string(&s, "BILLING_SETPOLICY");
      for(bsp=plan->root;bsp!=NULL;bsp=bsp->next) {
            if(!(p=(Policy*)PolicyL->getById(bsp->sp->pid))) continue;
            pd=u->ap->Add(p,bsp->sp->policy_flags);
            aDebug(DEBUG_BILLING, "  Policy %s(%06X) added to unit %s(%06X) from subplan %u\n", p->name, p->id, u->name, u->id, bsp->sp->id);
            print_to_string(&s, " %s %06X", p->name, p->id);
      }
      cAccessScriptCall(PASS, u, s);
      aFree(s);
      //set Unit flags
      if(u->ap->IsNetCheckBroken(u)) u->flags |= NETUNIT_BROKEN_ACCT_MF;
      else u->flags &= ~NETUNIT_BROKEN_ACCT_MF;
}

u_char Account::AddUnit(NetUnit *u, u_char flag) {
      bUlist *bu,*p=NULL;
      restrict_type action;

      for(bu=bUroot;bu!=NULL; bu=bu->next) {
            if(bu->u==u) break;
            p=bu;
      }

      if(flag) { //ADD
            if(bu) return 0;
            bu=(bUlist*)aMalloc(sizeof(bUlist));
            bu->u=u;
            bu->next=bUroot;
            bUroot=bu;
            u->account=this;
                  
            //set sys-policy and access for unit
            action=PASS;
            if (status&ACCOUNT_DENIED) {
                  action=DROP;
                  u->SetSysPolicy(SP_DENY_MONEY, ADD);
            } else {
                  u->SetSysPolicy(SP_DENY_MONEY, REMOVE);
            }

            if(status&ACCOUNT_BLOCKED) {
                  action=DROP;
                  u->SetSysPolicy(SP_DENY_BLOCK, ADD);
            } else {
                  u->SetSysPolicy(SP_DENY_BLOCK, REMOVE);
            }
      } else { //REMOVE
            if(!bu) return 0;
            u->account=NULL;
            if(bUroot==bu) bUroot=bUroot->next;
            else p->next=bu->next;
            aFree(bu);
            num_units--;
            
            //set sys-policy and access for unit
            action=DROP;
            u->SetSysPolicy(SP_DENY_MONEY, REMOVE);
            u->SetSysPolicy(SP_DENY_BLOCK, ADD);
            
      }
      cAccessScriptCall(action, u, "BILLING");
      aDebug(DEBUG_BILLING, "syspolicy for unit %s(%06X) set to %s\n", u->name?u->name:"<\?\?>", u->id, (action==PASS)?"PASS":"DROP");
      SetUnitAccountPolicy(u, flag);
      
      status|=ACCOUNT_NEED_SYNC;
//    changed=time(NULL);
      
      return 1;
}

void Account::AccountMessage(Message_Store *msg) {
      //do not charge fees from blocked && denied accounts accounts
//    if(status&(ACCOUNT_BLOCKED|ACCOUNT_DENIED)) return;

      if(!plan) return; //we have no plan to account
      
      SubPlan *sp;
      u_char poz=0;
      
      aDebug(DEBUG_BILLING, "Account msg:%p for unit:%06X policy:%06X in:%llu out:%llu\n", msg, msg->netunit, msg->ap, msg->data->in, msg->data->out);
      
      for(bSPlist *bsp=plan->root;bsp!=NULL; bsp=bsp->next, poz++) {
            sp=bsp->sp;
            if(sp->pid!=msg->ap) continue;

            //account
            data[poz].flow_in += msg->data->in;
            data[poz].flow_out += msg->data->out;
            status|=ACCOUNT_BDATA_NEED_SYNC;
            data[poz].flags|=BDATA_NEED_SYNC;
      }
}

FeeCounters* PrepareFeeCounters() {
      struct time_counters tc;
      struct tm t1;
      time_t delta,now;
      FeeCounters *fc=&FC;
      
      now=time(NULL);
      PrepareTimeCounters(&tc, now);
      
      //find seconds between this month and next
      localtime_r(&tc.mt, &t1);
      t1.tm_mon++;
      delta=(time_t)difftime(mktime(&t1), tc.mt);
      
      //generate traffic multiplier
      fc->traf_mult=(double)(tc.mt+delta-now)/delta;  //proportion for prepaid traffic left

      //copy time counters
      fc->now=now;
      fc->ht=tc.ht;
      fc->dt=tc.dt;
      fc->wt=tc.wt;
      fc->mt=tc.mt;

      //charge fee with precision 1 hour
      fc->hour_mult=(double)3600/delta;
      fc->day_mult =(double)(86400+tc.dt-tc.ht)/delta; //diff between now and next day begin
      fc->month_mult=(double)(delta+tc.mt-tc.ht)/delta; //diff betwen now and next month begin
      
      return fc;
}

void Account::ChargeFee() {

      //do not charge fees from blocked && denied accounts accounts
      if(status&(ACCOUNT_BLOCKED|ACCOUNT_DENIED)) return;
      
      if(!plan) return; //nothing to charge
      
      SubPlan *sp=NULL;
      double charge=0;
      double sp_charge;
      FeeCounters *fc=&FC;
      time_t now=fc->now;

      for (bSPlist *spl=plan->root; spl!=NULL; spl=spl->next){
            sp=spl->sp;
            
            if(!sp->fee) continue; // no fee
            
            switch(sp->spread) {
                  case 'H':
                        if(fc->ht <= last_fee_ch) continue;
                        if (sp->fee_adjust) sp_charge=sp->fee*fc->hour_mult;
                        else sp_charge=sp->fee;
                        break;
                  case 'D':
                        if(fc->dt <= last_fee_ch) continue;
                        if (sp->fee_adjust) sp_charge=sp->fee*fc->day_mult;
                        else sp_charge=sp->fee;
                        break;
                  case 'M':
                        if(fc->mt <= last_fee_ch) continue;
                        if (sp->fee_adjust) sp_charge=sp->fee*fc->month_mult;
                        else sp_charge=sp->fee;
                        break;
                  default:
                        sp_charge=0;
                        break;
            }
            if(sp_charge) {
                  charge+=sp_charge;
                  aDebug(DEBUG_BILLING, "periodic fee %lf for acc. %s, sp=%u, '%c', to charge %lf\n", sp_charge, name, sp->id, sp->spread, charge);
            }
      }
      
      if(charge==0) return; //nothing to charge

      if(balance-charge>=credit_limit) {
            balance-=charge;
            last_fee_ch=now;
            LogEvent(BILLING, 0, 0, id, "periodic fee %lf for acc. %s charged", charge, name);
            aDebug(DEBUG_BILLING, "periodic fee %lf for acc. %s charged\n", charge, name);
      } else {
            UpdateStatus(AC_DENY, now);
            aDebug(DEBUG_BILLING, "periodic fee %lf for acc. %s cannot be charged\n", charge, name);
      }
      status|=ACCOUNT_NEED_SYNC;
}

void Account::UpdateStatus(status_action action, time_t now) {
      NetUnit *u;
      const char *action_name=NULL;
      
      if (action==AC_DENY) {
            if(status&ACCOUNT_DENIED) return;
            status|=ACCOUNT_DENIED;
            action_name="DENY MONEY";
      } else if (action==AC_PASS) {
            if(!(status&ACCOUNT_DENIED)) return;
            status&=~ACCOUNT_DENIED;
            action_name="PASS MONEY";
      } else if(action==AC_BLOCK) {
            if(status&ACCOUNT_BLOCKED) return;
            status|=ACCOUNT_BLOCKED;
            status&=~ACCOUNT_BEBLOCKED;
            action_name="BLOCK";
            if(!blocked) blocked=now;
      } else if(action==AC_BEBLOCK) {
            if(status&ACCOUNT_BEBLOCKED) return;
            if(status&ACCOUNT_BLOCKED) return;
            status|=ACCOUNT_BEBLOCKED;
            action_name="BEBLOCK";
            if(!blocked) blocked=now;
      } else if(action==AC_UNBLOCK) {
            if((status&ACCOUNT_BEBLOCKED)) {
                  if(blocked) {
                        blocked=0;
                        status&=~ACCOUNT_BEBLOCKED;
                        status|=ACCOUNT_NEED_SYNC;
                        aDebug(DEBUG_BILLING, "account: %s(%06X) pending block removed\n", name, id);
                        action_name="UNBEBLOCK";
                  } 
                  return;
            }
            status&=~ACCOUNT_BLOCKED;
            action_name="UNBLOCK";
            blocked=0;
      }
      
      aDebug(DEBUG_BILLING, "account: %s(%06X) balance: %lf action: %s\n", name, id, balance, action_name);
      status|=ACCOUNT_NEED_SYNC;

      if(action==AC_BEBLOCK) return;

      restrict_type act;

      for (bUlist *bu=bUroot; bu!=NULL; bu=bu->next) {
            u=bu->u;
            act=PASS;

            if (action==AC_DENY) {
                  act=DROP;
                  u->SetSysPolicy(SP_DENY_MONEY, ADD);
            } else if (action==AC_PASS) {
                  u->SetSysPolicy(SP_DENY_MONEY, REMOVE);
            } else if(action==AC_BLOCK) {
                  act=DROP;
                  u->SetSysPolicy(SP_DENY_BLOCK, ADD);
            } else if(action==AC_UNBLOCK) {
                  u->SetSysPolicy(SP_DENY_BLOCK, REMOVE);
            }
            cAccessScriptCall(act, u, "BILLING");
            
            LogEvent(BILLING, u->id, 0, id, "syspolicy for unit %s(%06X) set to %s", u->name?u->name:"<\?\?>", u->id, (act==PASS)?"PASS":"DROP");
            aDebug(DEBUG_BILLING, "syspolicy for unit %s(%06X) set to %s\n", u->name?u->name:"<\?\?>", u->id,(act==PASS)?"PASS":"DROP");
      }
}

void Account::Balance(float amount, balance_action action){
      time_t now=FC.now;

      switch (action) {
            case BAL_ADD:
                  balance+=amount;
                  break;
            case BAL_REMOVE:
                  balance-=amount;
                  break;
            case BAL_SET:
                  balance=amount;
                  break;
      }
      
      //be sure about > or >= and < or <=
      if(status&ACCOUNT_DENIED) {
            if (balance >= credit_limit) {
                  status&=~ACCOUNT_DENIED;
                  ChargeFee();
                  if(!(status&ACCOUNT_DENIED)) {
                        status|=ACCOUNT_DENIED; //we need for correct UpdateStatus() 
                        UpdateStatus(AC_PASS, now);
                  }
            }
      } else if(balance<credit_limit) {
            UpdateStatus(AC_DENY, now);
      }

      status|=ACCOUNT_NEED_SYNC;
}

void Account::SyncAccount(FILE *bfile) {
      aDebug(DEBUG_BILLING, "sync request for account %06X %s\n", id, name?name:"<\?\?>");
      
      fprintf(bfile, "%u,%s,%s,%lf,", id, name,description?description:" ", balance);
      
      for (bUlist *bu=bUroot; bu!=NULL; bu=bu->next)
            fprintf(bfile, "%06X ", bu->u->id);

      fprintf(bfile, ",%u,%lu,%u,%lu,%lu,%lu,%lu,%lu,%s,%s,%u,%lf\n", plan?plan->id:0, plan_ch, nextplan?nextplan->id:0, nextplan_ch, blocked, created, changed, last_fee_ch, email?email:" ", password?password:" ", status, credit_limit);
      status&=~ACCOUNT_NEED_SYNC;
      
}

unsigned Account::SyncBdata(FILE *sfile) {
      time_t now=FC.now;
      u_char poz=0;
      unsigned num=0;
      double charge=0;
      double sum=0;
      long long delta=0;
      SubPlan *sp;
      billing_data *bd;
      
      aDebug(DEBUG_BILLING, "Bsync Account: %s(%06X) plan: %s(%u)\n", name, id, plan->name, plan->id);

      for(bSPlist *bsp=plan->root;bsp!=NULL; bsp=bsp->next, poz++) {
            if(data[poz].flags&BDATA_NEED_SYNC) {
                  sp=bsp->sp;
                  
                  bd=&data[poz];

                  if((sp->flags&SPLAN_SUM) && bd->m.in<0) {
                        //remember bd->m.in==bd->m.in until they preincluded 
                        //e.g. below 0
                        bd->m.in  += bd->flow_out;
                        bd->m.out += bd->flow_in;
                  }

                  delta=bd->flow_in;
                  //in
                  bd->m.in+=delta;
                  if(delta && bd->m.in>0) {
                        if (bd->m.in < delta) {
                              aDebug(DEBUG_BILLING, "Preincluded in traffic=%llu is over, switching to overdraft\n", sp->inc_in);
                              delta = bd->m.in;
                        }
                        bd->h.in+=delta;
                        bd->d.in+=delta;
                        bd->w.in+=delta;

                        if(!(sp->flags&SPLAN_UNLIM_IN)) {
                              charge=sp->overdraft_in*delta;
                              bd->h.pay_in+= charge;
                              bd->d.pay_in+= charge;
                              bd->w.pay_in+= charge;
                              bd->m.pay_in+= charge;
                        
                              sum+= charge;
                              aDebug(DEBUG_BILLING, "  subplan: %u over_in=%lld charge: %lf\n", sp->id, delta, charge);
                        }
                  }
                  
                  delta=bd->flow_out;
                  //out
                  bd->m.out+=delta;
                  if(delta && bd->m.out>0) {
                        if (bd->m.out < delta) {
                              aDebug(DEBUG_BILLING, "Preincluded out traffic=%llu is over, switching to overdraft\n", sp->inc_out);
                              delta = bd->m.out;
                        }
                        bd->h.out+=delta;
                        bd->d.out+=delta;
                        bd->w.out+=delta;

                        if(!(sp->flags&SPLAN_UNLIM_OUT)) {
                              charge = sp->overdraft_out*delta;
                              bd->h.pay_out+= charge;
                              bd->d.pay_out+= charge;
                              bd->w.pay_out+= charge;
                              bd->m.pay_out+= charge;

                              sum+= charge;
                              aDebug(DEBUG_BILLING, "  subplan: %u over_out=%lld  charge: %lf\n", sp->id, delta, charge);
                        }
                  }
                  
                  if(bd->m.in>0 || bd->m.out>0) {
                        fprintf(sfile, "%c,%u,%u,%lu,%lld,%lld,%lf,%lf\n",'H',id,bsp->sp->id,bd->h.from,bd->h.in,bd->h.out,bd->h.pay_in,bd->h.pay_out);
                        fprintf(sfile, "%c,%u,%u,%lu,%lld,%lld,%lf,%lf\n",'D',id,bsp->sp->id,bd->d.from,bd->d.in,bd->d.out,bd->d.pay_in,bd->d.pay_out);
                        fprintf(sfile, "%c,%u,%u,%lu,%lld,%lld,%lf,%lf\n",'W',id,bsp->sp->id,bd->w.from,bd->w.in,bd->w.out,bd->w.pay_in,bd->w.pay_out);
                        num+=3;
                  }
                  fprintf(sfile, "%c,%u,%u,%lu,%lld,%lld,%lf,%lf\n",'M',id,bsp->sp->id,bd->m.from,bd->m.in,bd->m.out,bd->m.pay_in,bd->m.pay_out);
                  num++;            

                  bd->flow_in=bd->flow_out=0;
                  data[poz].flags&=~BDATA_NEED_SYNC;
            }
      }
      
        //count money
      if(sum) {
            balance -= sum;
            aDebug(DEBUG_BILLING, "  Charged: %lf Balance: %lf\n", charge, balance);
            status|=ACCOUNT_NEED_SYNC;
            if(balance <= credit_limit) UpdateStatus(AC_DENY, now);
      }

      status&=~ACCOUNT_BDATA_NEED_SYNC;
      return num;
}     
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index