def deactivate_hardcoded_twilio_gateway_fees(apps, schema_editor): SmsGatewayFeeCriteria = apps.get_model('smsbillables', 'SmsGatewayFeeCriteria') to_deactivate = SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), country_code__isnull=False, is_active=True, ) remaining = SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), ).exclude( id__in=to_deactivate.values('id') ) assert remaining.count() == 2 assert remaining.filter(country_code=None).count() == 2 to_deactivate.update(is_active=False) assert SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), is_active=True, ).count() == 2 assert SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), country_code__isnull=True, is_active=True, ).count() == 2
def deactivate_hardcoded_twilio_gateway_fees(apps, schema_editor): SmsGatewayFeeCriteria = apps.get_model('smsbillables', 'SmsGatewayFeeCriteria') to_deactivate = SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), country_code__isnull=False, is_active=True, ) remaining = SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), ).exclude( id__in=to_deactivate.values('id')) assert remaining.count() == 2 assert remaining.filter(country_code=None).count() == 2 to_deactivate.update(is_active=False) assert SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), is_active=True, ).count() == 2 assert SmsGatewayFeeCriteria.objects.filter( backend_api_id=SQLTwilioBackend.get_api_id(), country_code__isnull=True, is_active=True, ).count() == 2
def setUpClass(cls): super(TestGatewayChargeWithAPISupport, cls).setUpClass() cls.domain = 'sms_test_api_domain' cls.backend = SQLTwilioBackend(name="TEST API BACKEND", is_global=True, domain=cls.domain, hq_api_id=SQLTwilioBackend.get_api_id()) cls.backend.save()
def post(self, request, api_key, *args, **kwargs): message_sid = request.POST.get('MessageSid') from_ = SQLTwilioBackend.convert_from_whatsapp( request.POST.get('From')) body = request.POST.get('Body') incoming_sms(from_, body, SQLTwilioBackend.get_api_id(), backend_message_id=message_sid, domain_scope=self.domain, backend_id=self.backend_couch_id) return HttpResponse(EMPTY_RESPONSE)
def test_twilio_multipart_usage_charge(self): self.apply_direction_fee() twilio_backend = SQLTwilioBackend.objects.create( name='TWILIO', is_global=True, hq_api_id=SQLTwilioBackend.get_api_id(), couch_id='global_backend', ) twilio_backend.set_extra_fields( account_sid='sid', auth_token='token', ) twilio_backend.save() messages = generator.arbitrary_messages_by_backend_and_direction( {twilio_backend.hq_api_id: twilio_backend.couch_id} ) for message in messages: FakeTwilioMessageFactory.add_num_segments_for_message(message.backend_message_id, randint(1, 10)) FakeTwilioMessageFactory.add_price_for_message(message.backend_message_id, generator.arbitrary_fee()) for message in messages: multipart_count = randint(1, 10) # Should be ignored billable = SmsBillable.create(message, multipart_count=multipart_count) self.assertIsNotNone(billable) self.assertEqual( billable.usage_charge, ( self.least_specific_fees[message.direction] * FakeTwilioMessageFactory.get_num_segments_for_message( message.backend_message_id ) ) )
def setUp(self): super(TwilioLogCallTestCase, self).setUp() self.backend = SQLTwilioBackend.objects.create( name='TWILIO', is_global=True, hq_api_id=SQLTwilioBackend.get_api_id() )
def test_twilio_domain_level_backend(self, mock_log_smsbillables_error): add_twilio_gateway_fee(apps) bootstrap_usage_fees(apps) twilio_backend = SQLTwilioBackend.objects.create( name='TWILIO', is_global=False, hq_api_id=SQLTwilioBackend.get_api_id(), couch_id='domain_backend', ) twilio_backend.set_extra_fields( account_sid='sid', auth_token='token', ) twilio_backend.save() messages = [ message for phone_number in [generator.arbitrary_phone_number() for _ in range(10)] for message in generator.arbitrary_messages_by_backend_and_direction( {twilio_backend.hq_api_id: twilio_backend.couch_id}, phone_number=phone_number) ] for msg_log in messages: FakeTwilioMessageFactory.add_price_for_message( msg_log.backend_message_id, generator.arbitrary_fee()) for msg_log in messages: multipart_count = randint(1, 10) # Should be ignored billable = SmsBillable.create(msg_log, multipart_count=multipart_count) self.assertIsNotNone(billable) self.assertIsNone(billable.gateway_fee) self.assertEqual(billable.gateway_charge, 0) self.assertEqual(mock_log_smsbillables_error.call_count, 0)
def _get_provider_charges(cls, backend_message_id, backend_instance, direction, couch_id, backend_api_id): if backend_message_id: if backend_api_id == SQLTwilioBackend.get_api_id(): message = get_twilio_message(backend_instance, backend_message_id) status = message.status price = message.price elif backend_api_id == InfobipBackend.get_api_id(): message = get_infobip_message(backend_instance, backend_message_id) status = message['status']['name'] price = message['price']['pricePerMessage'] else: raise ProviderFeeNotSupportedException("backend_message_id=%s" % backend_message_id) if status is None or status.lower() in [ 'accepted', 'queued', 'sending', 'receiving', ] or price is None: raise RetryBillableTaskException("backend_message_id=%s" % backend_message_id) return _ProviderChargeInfo( abs(Decimal(price)), SmsGatewayFee.get_by_criteria( backend_api_id, direction, ) ) else: log_smsbillables_error( "Could not create gateway fee for message %s: no backend_message_id" % couch_id ) return _ProviderChargeInfo(None, None)
def _available_gateway_fee_backends(): return [ backend for backend in get_sms_backend_classes().values() if backend.get_api_id() not in [SQLTwilioBackend.get_api_id(), InfobipBackend.get_api_id()] ]
def test_twilio_domain_level_backend(self, mock_log_smsbillables_error): add_twilio_gateway_fee(apps) bootstrap_usage_fees(apps) twilio_backend = SQLTwilioBackend.objects.create( name='TWILIO', is_global=False, hq_api_id=SQLTwilioBackend.get_api_id(), couch_id='domain_backend', ) twilio_backend.set_extra_fields( account_sid='sid', auth_token='token', ) twilio_backend.save() messages = [ message for phone_number in [generator.arbitrary_phone_number() for _ in range(10)] for message in generator.arbitrary_messages_by_backend_and_direction( {twilio_backend.hq_api_id: twilio_backend.couch_id}, phone_number=phone_number ) ] for msg_log in messages: FakeTwilioMessageFactory.add_price_for_message(msg_log.backend_message_id, generator.arbitrary_fee()) for msg_log in messages: multipart_count = randint(1, 10) # Should be ignored billable = SmsBillable.create(msg_log, multipart_count=multipart_count) self.assertIsNotNone(billable) self.assertIsNone(billable.gateway_fee) self.assertEqual(billable.gateway_charge, 0) self.assertEqual(mock_log_smsbillables_error.call_count, 0)
def ivr_in(request): if request.method == 'POST': from_number = request.POST.get('From') call_sid = request.POST.get('CallSid') log_call(from_number, '%s-%s' % (SQLTwilioBackend.get_api_id(), call_sid)) return HttpResponse(IVR_RESPONSE) else: return HttpResponseBadRequest("POST Expected")
def _get_twilio_client(backend_instance): from corehq.messaging.smsbackends.twilio.models import SQLTwilioBackend twilio_backend = SQLMobileBackend.load( backend_instance, api_id=SQLTwilioBackend.get_api_id(), is_couch_id=True, include_deleted=True ) config = twilio_backend.config return TwilioRestClient(config.account_sid, config.auth_token)
def _get_multipart_count(cls, backend_api_id, backend_instance, backend_message_id, multipart_count): if backend_api_id == SQLTwilioBackend.get_api_id(): twilio_message = get_twilio_message(backend_instance, backend_message_id) if twilio_message.num_segments is not None: return int(twilio_message.num_segments) else: raise RetryBillableTaskException("backend_message_id=%s" % backend_message_id) else: return multipart_count
def _get_twilio_client(backend_instance): from corehq.messaging.smsbackends.twilio.models import SQLTwilioBackend twilio_backend = SQLMobileBackend.load( backend_instance, api_id=SQLTwilioBackend.get_api_id(), is_couch_id=True, include_deleted=True, ) config = twilio_backend.config return Client(config.account_sid, config.auth_token)
def post(self, request, api_key, *args, **kwargs): message_sid = request.POST.get('MessageSid') account_sid = request.POST.get('AccountSid') from_ = request.POST.get('From') to = request.POST.get('To') body = request.POST.get('Body') incoming_sms(from_, body, SQLTwilioBackend.get_api_id(), backend_message_id=message_sid, backend_id=self.backend_couch_id) return HttpResponse(EMPTY_RESPONSE)
def post(self, request, api_key, *args, **kwargs): message_sid = request.POST.get('MessageSid') account_sid = request.POST.get('AccountSid') from_ = request.POST.get('From') to = request.POST.get('To') body = request.POST.get('Body') incoming_sms( from_, body, SQLTwilioBackend.get_api_id(), backend_message_id=message_sid, backend_id=self.backend_couch_id ) return HttpResponse(EMPTY_RESPONSE)
def setUp(self): self.client = Client() self.twilio_url = reverse(AddDomainGatewayView.urlname, kwargs={ 'domain': DOMAIN_NAME, 'hq_api_id': SQLTwilioBackend.get_api_id() }) self.telerivet_url = reverse(AddDomainGatewayView.urlname, kwargs={ 'domain': DOMAIN_NAME, 'hq_api_id': SQLTelerivetBackend.get_api_id() })
def add_twilio_gateway_fee(apps): default_currency, _ = apps.get_model( 'accounting', 'Currency').objects.get_or_create(code=settings.DEFAULT_CURRENCY) for direction in [INCOMING, OUTGOING]: SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), direction, None, fee_class=apps.get_model('smsbillables', 'SmsGatewayFee'), criteria_class=apps.get_model('smsbillables', 'SmsGatewayFeeCriteria'), currency=default_currency, )
def sms_in(request): if request.method == "POST": message_sid = request.POST.get("MessageSid") account_sid = request.POST.get("AccountSid") from_ = request.POST.get("From") to = request.POST.get("To") body = request.POST.get("Body") incoming_sms( from_, body, SQLTwilioBackend.get_api_id(), backend_message_id=message_sid ) return HttpResponse(EMPTY_RESPONSE) else: return HttpResponseBadRequest("POST Expected")
def add_twilio_gateway_fee(apps): default_currency, _ = apps.get_model( 'accounting', 'Currency' ).objects.get_or_create( code=settings.DEFAULT_CURRENCY ) for direction in [INCOMING, OUTGOING]: SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), direction, None, fee_class=apps.get_model('smsbillables', 'SmsGatewayFee'), criteria_class=apps.get_model('smsbillables', 'SmsGatewayFeeCriteria'), currency=default_currency, )
def _get_multipart_count(cls, backend_api_id, backend_instance, backend_message_id, multipart_count): if backend_api_id == SQLTwilioBackend.get_api_id(): twilio_message = get_twilio_message(backend_instance, backend_message_id) if twilio_message.num_segments is not None: return int(twilio_message.num_segments) else: raise RetryBillableTaskException("backend_message_id=%s" % backend_message_id) elif backend_api_id == InfobipBackend.get_api_id(): infobip_message = get_infobip_message(backend_instance, backend_message_id) segments = infobip_message['messageCount'] \ if 'messageCount' in infobip_message else infobip_message['smsCount'] if segments is not None: return int(segments) else: raise RetryBillableTaskException("backend_message_id=%s" % backend_message_id) else: return multipart_count
def bootstrap_twilio_gateway_incoming(apps): currency_class = apps.get_model('accounting', 'Currency') if apps else Currency sms_gateway_fee_class = apps.get_model('smsbillables', 'SmsGatewayFee') if apps else SmsGatewayFee sms_gateway_fee_criteria_class = apps.get_model('smsbillables', 'SmsGatewayFeeCriteria') if apps else SmsGatewayFeeCriteria # https://www.twilio.com/sms/pricing/us SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), INCOMING, 0.0075, country_code=None, currency=currency_class.objects.get(code="USD"), fee_class=sms_gateway_fee_class, criteria_class=sms_gateway_fee_criteria_class, ) log_smsbillables_info("Updated INCOMING Twilio gateway fees.")
def bootstrap_twilio_gateway_incoming(apps): currency_class = apps.get_model('accounting', 'Currency') if apps else Currency sms_gateway_fee_class = apps.get_model( 'smsbillables', 'SmsGatewayFee') if apps else SmsGatewayFee sms_gateway_fee_criteria_class = apps.get_model( 'smsbillables', 'SmsGatewayFeeCriteria') if apps else SmsGatewayFeeCriteria # https://www.twilio.com/sms/pricing/us SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), INCOMING, 0.0075, country_code=None, currency=currency_class.objects.get(code="USD"), fee_class=sms_gateway_fee_class, criteria_class=sms_gateway_fee_criteria_class, ) log_smsbillables_info("Updated INCOMING Twilio gateway fees.")
def _get_twilio_charges(cls, backend_message_id, backend_instance, direction, couch_id): if backend_message_id: twilio_message = get_twilio_message(backend_instance, backend_message_id) if twilio_message.status in [ 'accepted', 'queued', 'sending', 'receiving', ] or twilio_message.price is None: raise RetryBillableTaskException("backend_message_id=%s" % backend_message_id) return _TwilioChargeInfo( Decimal(twilio_message.price) * -1, SmsGatewayFee.get_by_criteria( SQLTwilioBackend.get_api_id(), direction, ) ) else: log_smsbillables_error( "Could not create gateway fee for Twilio message %s: no backend_message_id" % couch_id ) return _TwilioChargeInfo(None, None)
def _get_gateway_fee(cls, backend_api_id, backend_instance, phone_number, direction, couch_id, backend_message_id, domain): country_code, national_number = get_country_code_and_national_number( phone_number) is_gateway_billable = backend_instance is None or _sms_backend_is_global( backend_instance ) or toggles.ENABLE_INCLUDE_SMS_GATEWAY_CHARGING.enabled(domain) if is_gateway_billable: is_twilio_message = backend_api_id == SQLTwilioBackend.get_api_id() if is_twilio_message: twilio_charges = cls._get_twilio_charges( backend_message_id, backend_instance, direction, couch_id) gateway_fee = twilio_charges.gateway_fee direct_gateway_fee = twilio_charges.twilio_gateway_fee else: gateway_fee = SmsGatewayFee.get_by_criteria( backend_api_id, direction, backend_instance=backend_instance, country_code=country_code, national_number=national_number, ) direct_gateway_fee = None if gateway_fee: conversion_rate = gateway_fee.currency.rate_to_default if conversion_rate != 0: return _GatewayChargeInfo(gateway_fee, conversion_rate, direct_gateway_fee) else: log_smsbillables_error( "Gateway fee conversion rate for currency %s is 0" % gateway_fee.currency.code) return _GatewayChargeInfo(gateway_fee, None, direct_gateway_fee) else: log_smsbillables_error( "No matching gateway fee criteria for SMS %s" % couch_id) return _GatewayChargeInfo(None, None, None)
def _get_gateway_fee(cls, backend_api_id, backend_instance, phone_number, direction, couch_id, backend_message_id, domain): country_code, national_number = get_country_code_and_national_number(phone_number) is_gateway_billable = backend_instance is None or _sms_backend_is_global( backend_instance) or toggles.ENABLE_INCLUDE_SMS_GATEWAY_CHARGING.enabled(domain) if is_gateway_billable: is_twilio_message = backend_api_id == SQLTwilioBackend.get_api_id() if is_twilio_message: twilio_charges = cls._get_twilio_charges( backend_message_id, backend_instance, direction, couch_id ) gateway_fee = twilio_charges.gateway_fee direct_gateway_fee = twilio_charges.twilio_gateway_fee else: gateway_fee = SmsGatewayFee.get_by_criteria( backend_api_id, direction, backend_instance=backend_instance, country_code=country_code, national_number=national_number, ) direct_gateway_fee = None if gateway_fee: conversion_rate = gateway_fee.currency.rate_to_default if conversion_rate != 0: return _GatewayChargeInfo(gateway_fee, conversion_rate, direct_gateway_fee) else: log_smsbillables_error( "Gateway fee conversion rate for currency %s is 0" % gateway_fee.currency.code ) return _GatewayChargeInfo(gateway_fee, None, direct_gateway_fee) else: log_smsbillables_error( "No matching gateway fee criteria for SMS %s" % couch_id ) return _GatewayChargeInfo(None, None, None)
def post(self, request, api_key, *args, **kwargs): from_number = request.POST.get('From') call_sid = request.POST.get('CallSid') log_call(from_number, '%s-%s' % (SQLTwilioBackend.get_api_id(), call_sid)) return HttpResponse(IVR_RESPONSE)
def _available_gateway_fee_backends(): return filter( lambda backend: backend.get_api_id() != SQLTwilioBackend.get_api_id(), get_sms_backend_classes().values())
class AllBackendTest(BaseSMSTest): def setUp(self): super(AllBackendTest, self).setUp() self.domain_obj = Domain(name='all-backend-test') self.domain_obj.save() self.create_account_and_subscription(self.domain_obj.name) self.domain_obj = Domain.get(self.domain_obj._id) self.test_phone_number = '99912345' self.contact1 = CommCareCase(domain=self.domain_obj.name) self.contact1.set_case_property('contact_phone_number', self.test_phone_number) self.contact1.set_case_property('contact_phone_number_is_verified', '1') self.contact1.save() self.contact1 = CommConnectCase.wrap(self.contact1.to_json()) # For use with megamobile only self.contact2 = CommCareCase(domain=self.domain_obj.name) self.contact2.set_case_property('contact_phone_number', '63%s' % self.test_phone_number) self.contact2.set_case_property('contact_phone_number_is_verified', '1') self.contact2.save() self.contact2 = CommConnectCase.wrap(self.contact2.to_json()) self.unicel_backend = SQLUnicelBackend( name='UNICEL', is_global=True, hq_api_id=SQLUnicelBackend.get_api_id() ) self.unicel_backend.save() self.mach_backend = SQLMachBackend( name='MACH', is_global=True, hq_api_id=SQLMachBackend.get_api_id() ) self.mach_backend.save() self.tropo_backend = SQLTropoBackend( name='TROPO', is_global=True, hq_api_id=SQLTropoBackend.get_api_id() ) self.tropo_backend.save() self.http_backend = SQLHttpBackend( name='HTTP', is_global=True, hq_api_id=SQLHttpBackend.get_api_id() ) self.http_backend.save() self.telerivet_backend = SQLTelerivetBackend( name='TELERIVET', is_global=True, hq_api_id=SQLTelerivetBackend.get_api_id() ) self.telerivet_backend.set_extra_fields( **dict( webhook_secret='telerivet-webhook-secret' ) ) self.telerivet_backend.save() self.test_backend = SQLTestSMSBackend( name='TEST', is_global=True, hq_api_id=SQLTestSMSBackend.get_api_id() ) self.test_backend.save() self.grapevine_backend = SQLGrapevineBackend( name='GRAPEVINE', is_global=True, hq_api_id=SQLGrapevineBackend.get_api_id() ) self.grapevine_backend.save() self.twilio_backend = SQLTwilioBackend( name='TWILIO', is_global=True, hq_api_id=SQLTwilioBackend.get_api_id() ) self.twilio_backend.save() self.megamobile_backend = SQLMegamobileBackend( name='MEGAMOBILE', is_global=True, hq_api_id=SQLMegamobileBackend.get_api_id() ) self.megamobile_backend.save() self.smsgh_backend = SQLSMSGHBackend( name='SMSGH', is_global=True, hq_api_id=SQLSMSGHBackend.get_api_id() ) self.smsgh_backend.save() self.apposit_backend = SQLAppositBackend( name='APPOSIT', is_global=True, hq_api_id=SQLAppositBackend.get_api_id() ) self.apposit_backend.save() self.sislog_backend = SQLSislogBackend( name='SISLOG', is_global=True, hq_api_id=SQLSislogBackend.get_api_id() ) self.sislog_backend.save() self.yo_backend = SQLYoBackend( name='YO', is_global=True, hq_api_id=SQLYoBackend.get_api_id() ) self.yo_backend.save() def _test_outbound_backend(self, backend, msg_text, mock_send): SQLMobileBackendMapping.set_default_domain_backend(self.domain_obj.name, backend) send_sms(self.domain_obj.name, None, self.test_phone_number, msg_text) sms = SMS.objects.get( domain=self.domain_obj.name, direction='O', text=msg_text ) self.assertTrue(mock_send.called) msg_arg = mock_send.call_args[0][0] self.assertEqual(msg_arg.date, sms.date) self.assertEqual(sms.backend_api, backend.hq_api_id) self.assertEqual(sms.backend_id, backend.couch_id) def _verify_inbound_request(self, backend_api_id, msg_text, backend_couch_id=None): sms = SMS.objects.get( domain=self.domain_obj.name, direction='I', text=msg_text ) self.assertEqual(sms.backend_api, backend_api_id) if backend_couch_id: self.assertEqual(sms.backend_id, backend_couch_id) def _simulate_inbound_request_with_payload(self, url, content_type, payload): response = Client().post(url, payload, content_type=content_type) self.assertEqual(response.status_code, 200) def _simulate_inbound_request(self, url, phone_param, msg_param, msg_text, post=False, additional_params=None, expected_response_code=200): fcn = Client().post if post else Client().get payload = { phone_param: self.test_phone_number, msg_param: msg_text, } if additional_params: payload.update(additional_params) response = fcn(url, payload) self.assertEqual(response.status_code, expected_response_code) @patch('corehq.messaging.smsbackends.unicel.models.SQLUnicelBackend.send') @patch('corehq.messaging.smsbackends.mach.models.SQLMachBackend.send') @patch('corehq.messaging.smsbackends.tropo.models.SQLTropoBackend.send') @patch('corehq.messaging.smsbackends.http.models.SQLHttpBackend.send') @patch('corehq.messaging.smsbackends.telerivet.models.SQLTelerivetBackend.send') @patch('corehq.messaging.smsbackends.test.models.SQLTestSMSBackend.send') @patch('corehq.messaging.smsbackends.grapevine.models.SQLGrapevineBackend.send') @patch('corehq.messaging.smsbackends.twilio.models.SQLTwilioBackend.send') @patch('corehq.messaging.smsbackends.megamobile.models.SQLMegamobileBackend.send') @patch('corehq.messaging.smsbackends.smsgh.models.SQLSMSGHBackend.send') @patch('corehq.messaging.smsbackends.apposit.models.SQLAppositBackend.send') @patch('corehq.messaging.smsbackends.sislog.models.SQLSislogBackend.send') @patch('corehq.messaging.smsbackends.yo.models.SQLYoBackend.send') def test_outbound_sms( self, yo_send, sislog_send, apposit_send, smsgh_send, megamobile_send, twilio_send, grapevine_send, test_send, telerivet_send, http_send, tropo_send, mach_send, unicel_send): self._test_outbound_backend(self.unicel_backend, 'unicel test', unicel_send) self._test_outbound_backend(self.mach_backend, 'mach test', mach_send) self._test_outbound_backend(self.tropo_backend, 'tropo test', tropo_send) self._test_outbound_backend(self.http_backend, 'http test', http_send) self._test_outbound_backend(self.telerivet_backend, 'telerivet test', telerivet_send) self._test_outbound_backend(self.test_backend, 'test test', test_send) self._test_outbound_backend(self.grapevine_backend, 'grapevine test', grapevine_send) self._test_outbound_backend(self.twilio_backend, 'twilio test', twilio_send) self._test_outbound_backend(self.megamobile_backend, 'megamobile test', megamobile_send) self._test_outbound_backend(self.smsgh_backend, 'smsgh test', smsgh_send) self._test_outbound_backend(self.apposit_backend, 'apposit test', apposit_send) self._test_outbound_backend(self.sislog_backend, 'sislog test', sislog_send) self._test_outbound_backend(self.yo_backend, 'yo test', yo_send) def test_unicel_inbound_sms(self): self._simulate_inbound_request('/unicel/in/', phone_param=InboundParams.SENDER, msg_param=InboundParams.MESSAGE, msg_text='unicel test') self._verify_inbound_request(self.unicel_backend.get_api_id(), 'unicel test') def test_tropo_inbound_sms(self): tropo_data = {'session': {'from': {'id': self.test_phone_number}, 'initialText': 'tropo test'}} self._simulate_inbound_request_with_payload('/tropo/sms/', content_type='text/json', payload=json.dumps(tropo_data)) self._verify_inbound_request(self.tropo_backend.get_api_id(), 'tropo test') def test_telerivet_inbound_sms(self): additional_params = { 'event': 'incoming_message', 'message_type': 'sms', 'secret': self.telerivet_backend.config.webhook_secret } self._simulate_inbound_request('/telerivet/in/', phone_param='from_number_e164', msg_param='content', msg_text='telerivet test', post=True, additional_params=additional_params) self._verify_inbound_request(self.telerivet_backend.get_api_id(), 'telerivet test') @override_settings(SIMPLE_API_KEYS={'grapevine-test': 'grapevine-api-key'}) def test_grapevine_inbound_sms(self): xml = """ <gviSms> <smsDateTime>2015-10-12T12:00:00</smsDateTime> <cellNumber>99912345</cellNumber> <content>grapevine test</content> </gviSms> """ payload = urlencode({'XML': xml}) self._simulate_inbound_request_with_payload( '/gvi/api/sms/?apiuser=grapevine-test&apikey=grapevine-api-key', content_type='application/x-www-form-urlencoded', payload=payload) self._verify_inbound_request(self.grapevine_backend.get_api_id(), 'grapevine test') def test_twilio_inbound_sms(self): url = '/twilio/sms/%s' % self.twilio_backend.inbound_api_key self._simulate_inbound_request(url, phone_param='From', msg_param='Body', msg_text='twilio test', post=True) self._verify_inbound_request(self.twilio_backend.get_api_id(), 'twilio test', backend_couch_id=self.twilio_backend.couch_id) def test_twilio_401_response(self): start_count = SMS.objects.count() self._simulate_inbound_request('/twilio/sms/xxxxx', phone_param='From', msg_param='Body', msg_text='twilio test', post=True, expected_response_code=401) end_count = SMS.objects.count() self.assertEqual(start_count, end_count) def test_megamobile_inbound_sms(self): self._simulate_inbound_request('/megamobile/sms/', phone_param='cel', msg_param='msg', msg_text='megamobile test') self._verify_inbound_request(self.megamobile_backend.get_api_id(), 'megamobile test') def test_sislog_inbound_sms(self): self._simulate_inbound_request('/sislog/in/', phone_param='sender', msg_param='msgdata', msg_text='sislog test') self._verify_inbound_request(self.sislog_backend.get_api_id(), 'sislog test') def test_yo_inbound_sms(self): self._simulate_inbound_request('/yo/sms/', phone_param='sender', msg_param='message', msg_text='yo test') self._verify_inbound_request(self.yo_backend.get_api_id(), 'yo test') def test_smsgh_inbound_sms(self): user = ApiUser.create('smsgh-api-key', 'smsgh-api-key', permissions=[PERMISSION_POST_SMS]) user.save() self._simulate_inbound_request('/smsgh/sms/smsgh-api-key/', phone_param='snr', msg_param='msg', msg_text='smsgh test') self._verify_inbound_request('SMSGH', 'smsgh test') user.delete() def test_apposit_inbound_sms(self): user = ApiUser.create('apposit-api-key', 'apposit-api-key', permissions=[PERMISSION_POST_SMS]) user.save() self._simulate_inbound_request( '/apposit/in/apposit-api-key/', phone_param='fromAddress', msg_param='content', msg_text='apposit test', post=True, additional_params={'channel': 'SMS'} ) self._verify_inbound_request('APPOSIT', 'apposit test') user.delete() def tearDown(self): delete_domain_phone_numbers(self.domain_obj.name) self.contact1.delete() self.contact2.delete() self.domain_obj.delete() self.unicel_backend.delete() self.mach_backend.delete() self.tropo_backend.delete() self.http_backend.delete() self.telerivet_backend.delete() self.test_backend.delete() self.grapevine_backend.delete() self.twilio_backend.delete() self.megamobile_backend.delete() self.smsgh_backend.delete() self.apposit_backend.delete() self.sislog_backend.delete() self.yo_backend.delete() super(AllBackendTest, self).tearDown()
def setUp(self): super(AllBackendTest, self).setUp() self.domain_obj = Domain(name='all-backend-test') self.domain_obj.save() self.create_account_and_subscription(self.domain_obj.name) self.domain_obj = Domain.get(self.domain_obj._id) self.test_phone_number = '99912345' self.contact1 = CommCareCase(domain=self.domain_obj.name) self.contact1.set_case_property('contact_phone_number', self.test_phone_number) self.contact1.set_case_property('contact_phone_number_is_verified', '1') self.contact1.save() self.contact1 = CommConnectCase.wrap(self.contact1.to_json()) # For use with megamobile only self.contact2 = CommCareCase(domain=self.domain_obj.name) self.contact2.set_case_property('contact_phone_number', '63%s' % self.test_phone_number) self.contact2.set_case_property('contact_phone_number_is_verified', '1') self.contact2.save() self.contact2 = CommConnectCase.wrap(self.contact2.to_json()) self.unicel_backend = SQLUnicelBackend( name='UNICEL', is_global=True, hq_api_id=SQLUnicelBackend.get_api_id() ) self.unicel_backend.save() self.mach_backend = SQLMachBackend( name='MACH', is_global=True, hq_api_id=SQLMachBackend.get_api_id() ) self.mach_backend.save() self.tropo_backend = SQLTropoBackend( name='TROPO', is_global=True, hq_api_id=SQLTropoBackend.get_api_id() ) self.tropo_backend.save() self.http_backend = SQLHttpBackend( name='HTTP', is_global=True, hq_api_id=SQLHttpBackend.get_api_id() ) self.http_backend.save() self.telerivet_backend = SQLTelerivetBackend( name='TELERIVET', is_global=True, hq_api_id=SQLTelerivetBackend.get_api_id() ) self.telerivet_backend.set_extra_fields( **dict( webhook_secret='telerivet-webhook-secret' ) ) self.telerivet_backend.save() self.test_backend = SQLTestSMSBackend( name='TEST', is_global=True, hq_api_id=SQLTestSMSBackend.get_api_id() ) self.test_backend.save() self.grapevine_backend = SQLGrapevineBackend( name='GRAPEVINE', is_global=True, hq_api_id=SQLGrapevineBackend.get_api_id() ) self.grapevine_backend.save() self.twilio_backend = SQLTwilioBackend( name='TWILIO', is_global=True, hq_api_id=SQLTwilioBackend.get_api_id() ) self.twilio_backend.save() self.megamobile_backend = SQLMegamobileBackend( name='MEGAMOBILE', is_global=True, hq_api_id=SQLMegamobileBackend.get_api_id() ) self.megamobile_backend.save() self.smsgh_backend = SQLSMSGHBackend( name='SMSGH', is_global=True, hq_api_id=SQLSMSGHBackend.get_api_id() ) self.smsgh_backend.save() self.apposit_backend = SQLAppositBackend( name='APPOSIT', is_global=True, hq_api_id=SQLAppositBackend.get_api_id() ) self.apposit_backend.save() self.sislog_backend = SQLSislogBackend( name='SISLOG', is_global=True, hq_api_id=SQLSislogBackend.get_api_id() ) self.sislog_backend.save() self.yo_backend = SQLYoBackend( name='YO', is_global=True, hq_api_id=SQLYoBackend.get_api_id() ) self.yo_backend.save()
def _available_gateway_fee_backends(): return filter( lambda backend: backend.get_api_id() != SQLTwilioBackend.get_api_id(), get_sms_backend_classes().values() )
def validate_phone_number(self, phone_number: str) -> None: from corehq.messaging.smsbackends.twilio.models import SQLTwilioBackend if not SQLTwilioBackend.phone_number_is_messaging_service_sid( phone_number): super().validate_phone_number(phone_number)
def bootstrap_twilio_gateway(apps, twilio_rates_filename): currency_class = apps.get_model('accounting', 'Currency') if apps else Currency sms_gateway_fee_class = apps.get_model('smsbillables', 'SmsGatewayFee') if apps else SmsGatewayFee sms_gateway_fee_criteria_class = apps.get_model('smsbillables', 'SmsGatewayFeeCriteria') if apps else SmsGatewayFeeCriteria # iso -> provider -> rate def get_twilio_data(): twilio_file = open(twilio_rates_filename) twilio_csv = csv.reader(twilio_file.read().splitlines()) twilio_data = {} skip = 0 for row in twilio_csv: if skip < 4: skip += 1 continue else: try: iso = row[0].lower() provider = row[2].split('-')[1].lower().replace(' ', '') rate = float(row[3]) if not(iso in twilio_data): twilio_data[iso] = {} twilio_data[iso][provider] = rate except IndexError: log_smsbillables_info("Twilio index error %s:" % row) twilio_file.close() return twilio_data # iso -> provider -> (country code, number of subscribers) def get_mach_data(): mach_workbook = xlrd.open_workbook('corehq/apps/smsbillables/management/' 'commands/pricing_data/Syniverse_coverage_list_DIAMONDplus.xls') mach_table = mach_workbook.sheet_by_index(0) mach_data = {} try: row = 7 while True: country_code = int(mach_table.cell_value(row, 0)) iso = mach_table.cell_value(row, 1) network = mach_table.cell_value(row, 5).lower().replace(' ', '') subscribers = 0 try: subscribers = int(mach_table.cell_value(row, 10).replace('.', '')) except ValueError: log_smsbillables_info("Incomplete subscriber data for country code %d" % country_code) if not(iso in mach_data): mach_data[iso] = {} mach_data[iso][network] = (country_code, subscribers) row += 1 except IndexError: pass return mach_data twilio_data = get_twilio_data() mach_data = get_mach_data() for iso in twilio_data: if iso in mach_data: weighted_price = 0 total_subscriptions = 0 country_code = None calculate_other = False for twilio_provider in twilio_data[iso]: if twilio_provider == 'other': calculate_other = True else: for mach_provider in mach_data[iso]: try: if twilio_provider in mach_provider: country_code, subscriptions = mach_data[iso][mach_provider] weighted_price += twilio_data[iso][twilio_provider] * subscriptions total_subscriptions += subscriptions mach_data[iso][mach_provider] = country_code, 0 break except UnicodeDecodeError: pass if calculate_other: other_rate_twilio = twilio_data[iso]['other'] for _, subscriptions in mach_data[iso].values(): weighted_price += other_rate_twilio * subscriptions total_subscriptions += subscriptions if country_code is not None: weighted_price = weighted_price / total_subscriptions SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), OUTGOING, weighted_price, country_code=country_code, currency=currency_class.objects.get(code="USD"), fee_class=sms_gateway_fee_class, criteria_class=sms_gateway_fee_criteria_class, ) else: log_smsbillables_info("%s not in mach_data" % iso) # https://www.twilio.com/help/faq/sms/will-i-be-charged-if-twilio-encounters-an-error-when-sending-an-sms SmsGatewayFee.create_new( SQLTwilioBackend.get_api_id(), OUTGOING, 0.00, country_code=None, currency=currency_class.objects.get(code="USD"), fee_class=sms_gateway_fee_class, criteria_class=sms_gateway_fee_criteria_class, ) log_smsbillables_info("Updated Twilio gateway fees.")
def _available_gateway_fee_backends(): return [ backend for backend in get_sms_backend_classes().values() if backend.get_api_id() != SQLTwilioBackend.get_api_id() ]