def fsapi(session, stream, env, args): """Handles data from the FS API. Args: string of the form <service_type>|<call_or_sms>|<destination_number> """ service_type, call_or_sms, destination_number = args.split('|') # Sanitize the destination number. destination_number = number_utilities.strip_number(destination_number) res = str(billing.get_service_tariff( service_type, call_or_sms, destination_number=destination_number)) consoleLog('info', "Returned FSAPI: " + res + "\n") stream.write(res)
def chat(message, args): """Handles data from the chatplan. Args: string of the form <service_type>|<call_or_sms>|<destination_number> """ service_type, call_or_sms, destination_number = args.split('|') # Sanitize the destination number. destination_number = number_utilities.strip_number(destination_number) res = str(billing.get_service_tariff( service_type, call_or_sms, destination_number=destination_number)) consoleLog('info', "Returned Chat: " + res + "\n") message.chat_execute('set', 'service_type=%s' % res)
def process_cdr(self, cdr_xml): """Processes the XML CDR for the caller.""" cdr_dom = xml.parseString(cdr_xml) # Handle only b-legs for billing. origin = cdr_dom.getElementsByTagName("origination") if origin: return # Handle only b-legs for billing. # For our purposes, billsec is how long the call lasted. call_duration # captures the amount of time spent ringing, which we don't charge for, # so don't include here. Caller and callee are just used for logging # and reason statements. # TODO(matt): what happens if the tag does not exist? call_duration = int( get_tag_text( cdr_dom.getElementsByTagName("duration")[0].childNodes)) billsec = int( get_tag_text( cdr_dom.getElementsByTagName("billsec")[0].childNodes)) # In b-leg cdrs, there are multiple destinations -- the sip one (IMSI) # and the dialed one (MSISDN). We want the latter. callees = cdr_dom.getElementsByTagName("destination_number") callee = '' for c in callees: c = get_tag_text(c.childNodes) # NOT THE IMSI if c[0:4] != IMSI_PREFIX: callee = c break if callee[0] == "+": callee = callee[1:] hangupcause = get_hangup_cause(cdr_dom) # This is where we get the info we need to do billing. if len(cdr_dom.getElementsByTagName("service_type")) > 0: service_type = get_tag_text( cdr_dom.getElementsByTagName("service_type")[0].childNodes) # Get caller / callee info. See the 'CDR notes' doc in drive for # more info. from_imsi, from_number, to_imsi, to_number = 4 * [None] # We always get 'from_imsi' from the <username> tag with the # <caller_profile> parent element. If it's a BTS-originated call, # this will be an IMSI; otherwise, it'll be an MSISDN. if service_type not in ['incoming_call']: elements = cdr_dom.getElementsByTagName('username') for element in elements: if element.parentNode.nodeName == 'caller_profile': username = get_tag_text(element.childNodes) from_imsi = subscriber.get_imsi_from_username(username) break # Get 'from_number' (only available for outside and local calls). if service_type in ['outside_call', 'local_call', 'incoming_call']: elements = cdr_dom.getElementsByTagName('caller_id_name') for element in elements: if element.parentNode.nodeName == 'caller_profile': from_number = get_tag_text(element.childNodes) break # Get 'to_imsi' (only available for local/incoming calls). if service_type in ['local_call', 'incoming_call']: elements = cdr_dom.getElementsByTagName('callee_id_number') for element in elements: if element.parentNode.nodeName == 'caller_profile': callee_id = get_tag_text(element.childNodes) if callee_id[0:4] == IMSI_PREFIX: to_imsi = callee_id else: # callee_id_number in the CDR is MSISDN. to_imsi = subscriber.get_imsi_from_number( callee_id) break # Get 'to_number' (slightly different for local/incoming calls). if service_type in ['outside_call', 'free_call', 'error_call']: elements = cdr_dom.getElementsByTagName('destination_number') for element in elements: if element.parentNode.nodeName == 'caller_profile': to_number = get_tag_text(element.childNodes) break elif service_type in ['local_call', 'incoming_call']: elements = cdr_dom.getElementsByTagName('destination_number') for element in elements: if (element.parentNode.nodeName == 'originator_caller_profile'): to_number = get_tag_text(element.childNodes) break # Generate billing information for the caller, if the caller is # local to the BTS. if service_type != 'incoming_call': tariff = billing.get_service_tariff( service_type, 'call', destination_number=to_number) cost = billing.get_call_cost(billsec, service_type, destination_number=to_number) reason = "%s sec call to %s (%s/%s)" % ( billsec, to_number, service_type, hangupcause) old_balance = subscriber.get_account_balance(from_imsi) subscriber.subtract_credit(from_imsi, str(cost)) owner_imsi = from_imsi kind = service_type events.create_call_event(owner_imsi, from_imsi, from_number, to_imsi, to_number, old_balance, cost, kind, reason, tariff, call_duration, billsec) # Create a call record for the callee, if applicable. if service_type in ['local_call', 'incoming_call']: if service_type == 'local_call': service_type = 'local_recv_call' tariff = billing.get_service_tariff(service_type, 'call') cost = billing.get_call_cost(billsec, service_type) reason = "%d sec call from %s (%s/%s)" % ( billsec, from_number, service_type, hangupcause) # Note! This is different than how we bill for a caller -- # we're deducting from the 'to_imsi' (the callee) instead. old_balance = subscriber.get_account_balance(to_imsi) subscriber.subtract_credit(to_imsi, str(cost)) owner_imsi = to_imsi kind = service_type events.create_call_event(owner_imsi, from_imsi, from_number, to_imsi, to_number, old_balance, cost, kind, reason, tariff, call_duration, billsec) else: username = get_tag_text( cdr_dom.getElementsByTagName("username")[0].childNodes) from_imsi = subscriber.get_imsi_from_username(username) message = "No rate info for this call. (from: %s, billsec: %s)" % ( from_imsi, billsec) logger.error(message)
def post(self, request, format=None): needed_fields = ["imsi", "trans", "dest"] if not all(i in request.POST for i in needed_fields): return Response("Missing Args", status=status.HTTP_400_BAD_REQUEST) promo_type, service_type = extract_types(request.data['trans']) imsi = request.data['imsi'] dest = request.data['dest'] # Assume first that regular tariffs will be applied # then overwrite later if promos apply. # Kinda weird, but this avoid 'ret' being unset if Disc # promo is suddenly purged by celery while traversing FS dialplan if 'sms' in service_type: call_or_sms = 'sms' else: call_or_sms = 'call' destination_number = number_utilities.strip_number(dest) # Kludge! if 'globe' in service_type: # replace first word with globe keyword ret = str( billing.get_service_tariff( 'outside_' + service_type.split('_')[1], call_or_sms, destination_number)) else: ret = str( billing.get_service_tariff(service_type, call_or_sms, destination_number)) # if unli or bulk, no tariff if promo_type == 'U' or promo_type == 'B': ret = '0' # if discounted, get tariff from earliest subscribed discounted promo elif promo_type in ['D']: query = service_type + '__gt' promo = PromoSubscription.objects.filter( contact__imsi__exact=imsi, promo__promo_type=promo_type, **{ query: 0 }).order_by('date_expiration') if promo: key = 'promo[0].%s' % service_type ret = str(eval(key)) # else, regular tariffs from above will apply elif promo_type in ['G']: query = service_type + '__gt' promo = PromoSubscription.objects.filter( contact__imsi__exact=imsi, promo__promo_type=promo_type, **{ query: 0 }).order_by('date_expiration') member = GroupMembers.objects.filter( group__owner__imsi__exact=imsi, user__callerid__exact=dest) if promo and member: key = 'promo[0].%s' % service_type ret = str(eval(key)) # else, regular tariffs from above will apply return Response(ret, status=status.HTTP_200_OK)