def test_off_receive_call(self): """We can get the subscriber price for an off-network received call.""" billable_seconds = 700 expected_cost = 1200 self.assertEqual( expected_cost, get_call_cost(billable_seconds, 'off_network_receive'))
def test_on_receive_call(self): """We can get the subscriber price for an on-network received call.""" billable_seconds = 170 # Recall that the expected cost is rounded to the nearest value of 100. expected_cost = 600 self.assertEqual(expected_cost, get_call_cost(billable_seconds, 'on_network_receive'))
def test_call_to_ph(self): """ We bill for calls to PH correctly. """ billable_seconds = 70 expected_cost = 900 number = ''.join(['63', '5551234567']) actual_cost = get_call_cost(billable_seconds, 'off_network_send', destination_number=number) self.assertEqual(expected_cost, actual_cost)
def test_call_to_chile(self): """We can get the cost of a call to Chile.""" billable_seconds = 830 expected_cost = 11000 number = ''.join(['56', '1235554567']) actual_cost = get_call_cost(billable_seconds, 'off_network_send', destination_number=number) self.assertEqual(expected_cost, actual_cost)
def test_on_send_call(self): """We can get the subscriber price for an on-network sent call.""" billable_seconds = 190 expected_cost = 1000 self.assertEqual(expected_cost, get_call_cost(billable_seconds, 'on_network_send'))
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)