<commit_before>from random import randint

from django.conf import settings
from django.test import TestCase
from corehq.apps.accounting.generator import init_default_currency

from corehq.apps.smsbillables.models import *
from corehq.apps.smsbillables import generator
from corehq.apps.sms.models import SQLMobileBackend


class TestUsageFee(TestCase):
    def setUp(self):
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()

        self.currency_usd = init_default_currency()

        self.least_specific_fees = generator.arbitrary_fees_by_direction()
        self.most_specific_fees = generator.arbitrary_fees_by_direction_and_domain()
        self.backend_ids = generator.arbitrary_backend_ids()

    def apply_direction_fee(self):
        for direction, amount in self.least_specific_fees.items():
            SmsUsageFee.create_new(direction, amount)

    def apply_direction_and_domain_fee(self):
        for direction, domain_fee in self.most_specific_fees.items():
            for domain, amount in domain_fee.items():
                SmsUsageFee.create_new(direction, amount, domain=domain)

    def test_only_direction(self):
        self.apply_direction_fee()
        messages = generator.arbitrary_messages_by_backend_and_direction(self.backend_ids)

        for message in messages:
            billable = SmsBillable.create(message)
            self.assertIsNotNone(billable)
            self.assertEqual(
                billable.usage_charge,
                self.least_specific_fees[message.direction]
            )

    def test_domain_and_direction(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                )
                for message in messages:
                    billable = SmsBillable.create(message)
                    self.assertIsNotNone(billable)
                    self.assertEqual(
                        billable.usage_charge,
                        self.most_specific_fees[message.direction][domain]
                    )

    def test_multipart_usage_charge(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                )
                for message in messages:
                    multipart_count = randint(1, 10)
                    billable = SmsBillable.create(message, multipart_count=multipart_count)
                    self.assertIsNotNone(billable)
                    self.assertEqual(
                        billable.usage_charge,
                        self.most_specific_fees[message.direction][domain] * multipart_count
                    )

    def test_log_no_usage_fee(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                    directions=['X', 'Y'],
                )
                for message in messages:
                    billable = SmsBillable.create(message)
                    self.assertIsNotNone(billable)
                    self.assertIsNone(billable.usage_fee)

    def tearDown(self):
        SmsBillable.objects.all().delete()
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()
        SmsGatewayFee.objects.all().delete()
        self.currency_usd.delete()
        for api_id, backend_id in self.backend_ids.iteritems():
            SQLMobileBackend.load(backend_id, is_couch_id=True).delete()
<commit_msg>test usage charges for twilio<commit_after>from mock import patch
from random import randint

from django.test import TestCase

from corehq.apps.accounting.generator import init_default_currency
from corehq.apps.smsbillables import generator
from corehq.apps.sms.models import SQLMobileBackend
from corehq.apps.smsbillables.models import (
    SmsBillable,
    SmsGatewayFee,
    SmsUsageFee,
    SmsUsageFeeCriteria,
)
from corehq.apps.smsbillables.tests import FakeTwilioMessageFactory
from corehq.messaging.smsbackends.twilio.models import SQLTwilioBackend


class TestUsageFee(TestCase):
    def setUp(self):
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()

        self.currency_usd = init_default_currency()

        self.least_specific_fees = generator.arbitrary_fees_by_direction()
        self.most_specific_fees = generator.arbitrary_fees_by_direction_and_domain()
        self.backend_ids = generator.arbitrary_backend_ids()

    def apply_direction_fee(self):
        for direction, amount in self.least_specific_fees.items():
            SmsUsageFee.create_new(direction, amount)

    def apply_direction_and_domain_fee(self):
        for direction, domain_fee in self.most_specific_fees.items():
            for domain, amount in domain_fee.items():
                SmsUsageFee.create_new(direction, amount, domain=domain)

    def test_only_direction(self):
        self.apply_direction_fee()
        messages = generator.arbitrary_messages_by_backend_and_direction(self.backend_ids)

        for message in messages:
            billable = SmsBillable.create(message)
            self.assertIsNotNone(billable)
            self.assertEqual(
                billable.usage_charge,
                self.least_specific_fees[message.direction]
            )

    def test_domain_and_direction(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                )
                for message in messages:
                    billable = SmsBillable.create(message)
                    self.assertIsNotNone(billable)
                    self.assertEqual(
                        billable.usage_charge,
                        self.most_specific_fees[message.direction][domain]
                    )

    def test_multipart_usage_charge(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                )
                for message in messages:
                    multipart_count = randint(1, 10)
                    billable = SmsBillable.create(message, multipart_count=multipart_count)
                    self.assertIsNotNone(billable)
                    self.assertEqual(
                        billable.usage_charge,
                        self.most_specific_fees[message.direction][domain] * multipart_count
                    )

    @patch(
        'twilio.rest.resources.messages.Messages.get',
        lambda self, message_id: FakeTwilioMessageFactory.get_message(message_id)
    )
    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 test_log_no_usage_fee(self):
        self.apply_direction_fee()
        self.apply_direction_and_domain_fee()

        for direction, domain_fee in self.most_specific_fees.items():
            for domain in domain_fee:
                messages = generator.arbitrary_messages_by_backend_and_direction(
                    self.backend_ids,
                    domain=domain,
                    directions=['X', 'Y'],
                )
                for message in messages:
                    billable = SmsBillable.create(message)
                    self.assertIsNotNone(billable)
                    self.assertIsNone(billable.usage_fee)

    def tearDown(self):
        SmsBillable.objects.all().delete()
        SmsUsageFee.objects.all().delete()
        SmsUsageFeeCriteria.objects.all().delete()
        SmsGatewayFee.objects.all().delete()
        self.currency_usd.delete()
        for api_id, backend_id in self.backend_ids.iteritems():
            SQLMobileBackend.load(backend_id, is_couch_id=True).delete()

        FakeTwilioMessageFactory.backend_message_id_to_price = {}

{'fraction_non_alphanumeric': 0.07168598422129152, 'fraction_numerical': 0.0011687932209993182, 'mean_word_length': 2.1710932674490424, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3011556', 'n_tokens_mistral': 2894, 'n_tokens_neox': 2745, 'n_words': 428}