Esempio n. 1
0
def confirm_service_invoice_payment(request, *args, **kwargs):
    """
    This view is run after successful user cashout "MOMO_AFTER_CHECKOUT"
    """
    status = request.GET['status']
    message = request.GET['message']
    operator_tx_id = request.GET['operator_tx_id']
    phone = request.GET['phone']
    tx_id = kwargs['tx_id']
    extra_months = int(kwargs['extra_months'])
    try:
        tx = MoMoTransaction.objects.using(WALLETS_DB_ALIAS).get(pk=tx_id, is_running=True)
        if not getattr(settings, 'DEBUG', False):
            tx_timeout = getattr(settings, 'IKWEN_PAYMENT_GATEWAY_TIMEOUT', 15) * 60
            expiry = tx.created_on + timedelta(seconds=tx_timeout)
            if datetime.now() > expiry:
                return HttpResponse("Transaction %s timed out." % tx_id)

        tx.status = status
        tx.message = 'OK' if status == MoMoTransaction.SUCCESS else message
        tx.processor_tx_id = operator_tx_id
        tx.phone = phone
        tx.is_running = False
        tx.save()
    except:
        raise Http404("Transaction %s not found" % tx_id)
    if status != MoMoTransaction.SUCCESS:
        return HttpResponse("Notification for transaction %s received with status %s" % (tx_id, status))
    invoice_id = tx.object_id
    amount = tx.amount
    signature = tx.task_id

    callback_signature = kwargs.get('signature')
    no_check_signature = request.GET.get('ncs')
    if getattr(settings, 'DEBUG', False):
        if not no_check_signature:
            if callback_signature != signature:
                return HttpResponse('Invalid transaction signature')
    else:
        if callback_signature != signature:
            return HttpResponse('Invalid transaction signature')
    now = datetime.now()
    ikwen_service = get_service_instance()
    invoice = Invoice.objects.get(pk=invoice_id)
    invoice.paid += amount
    invoice.status = Invoice.PAID
    invoice.save()
    payment = Payment.objects.create(invoice=invoice, method=Payment.MOBILE_MONEY,
                                     amount=amount, processor_tx_id=tx.processor_tx_id)
    service = invoice.service
    total_months = invoice.months_count + extra_months
    days = get_days_count(total_months)
    invoicing_config = get_invoicing_config_instance()
    if service.status == Service.SUSPENDED:
        days -= invoicing_config.tolerance  # Catch-up days that were offered before service suspension
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    elif service.expiry:
        expiry = service.expiry + timedelta(days=days)
    else:
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    service.expiry = expiry
    service.status = Service.ACTIVE
    if invoice.is_one_off:
        service.version = Service.FULL
        try:
            support_bundle = SupportBundle.objects.get(type=SupportBundle.TECHNICAL, channel=SupportBundle.PHONE, cost=0)
            token = ''.join([random.SystemRandom().choice(string.digits) for i in range(6)])
            support_expiry = now + timedelta(days=support_bundle.duration)
            SupportCode.objects.create(service=service, token=token, bundle=support_bundle,
                                       balance=support_bundle.quantity, expiry=support_expiry)
            logger.debug("Free Support Code created for %s" % service)
        except SupportBundle.DoesNotExist:
            logger.error("Free Support Code not created for %s" % service, exc_info=True)
    service.save()
    mean = tx.wallet
    is_early_payment = False
    if service.app.slug == 'kakocase' or service.app.slug == 'webnode':
        if invoice.due_date <= now.date():
            is_early_payment = True
        refill_tsunami_messaging_bundle(service, is_early_payment)
    share_payment_and_set_stats(invoice, total_months, mean)
    member = service.member
    vendor = service.retailer
    vendor_is_dara = vendor and vendor.app.slug == DARAJA
    if vendor and not vendor_is_dara:
        add_database_to_settings(vendor.database)
        sudo_group = Group.objects.using(vendor.database).get(name=SUDO)
    else:
        vendor = ikwen_service
        sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor, PAYMENT_CONFIRMATION, member=member, object_id=invoice.id)
    add_event(vendor, PAYMENT_CONFIRMATION, group_id=sudo_group.id, object_id=invoice.id)

    try:
        invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
    except:
        invoice_pdf_file = None

    if member.email:
        activate(member.language)
        invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,))
        subject, message, sms_text = get_payment_confirmation_message(payment, member)
        html_content = get_mail_content(subject, message, service=vendor, template_name='billing/mails/notice.html',
                                        extra_context={'member_name': member.first_name, 'invoice': invoice,
                                                       'cta': _("View invoice"), 'invoice_url': invoice_url,
                                                       'early_payment': is_early_payment})
        sender = '%s <no-reply@%s>' % (vendor.config.company_name, ikwen_service.domain)
        msg = XEmailMessage(subject, html_content, sender, [member.email])
        if vendor != ikwen_service and not vendor_is_dara:
            msg.service = vendor
        if invoice_pdf_file:
            msg.attach_file(invoice_pdf_file)
        msg.content_subtype = "html"
        if getattr(settings, 'UNIT_TESTING', False):
            msg.send()
        else:
            Thread(target=lambda m: m.send(), args=(msg,)).start()
    return HttpResponse("Notification received")
Esempio n. 2
0
def confirm_service_invoice_payment(request, *args, **kwargs):
    """
    This view is run after successful user cashout "MOMO_AFTER_CHECKOUT"
    """
    tx = kwargs[
        'tx']  # Decoration with @momo_gateway_callback makes 'tx' available in kwargs
    extra_months = int(kwargs['extra_months'])
    payment = Payment.objects.select_related().get(pk=tx.object_id)
    payment.processor_tx_id = tx.processor_tx_id
    payment.save()
    invoice = payment.invoice
    now = datetime.now()
    ikwen_service = get_service_instance()
    invoice.paid += tx.amount
    if invoice.paid >= invoice.amount:
        invoice.status = Invoice.PAID
    invoice.save()
    service = invoice.service
    total_months = invoice.months_count + extra_months
    days = get_days_count(total_months)
    invoicing_config = get_invoicing_config_instance()
    if service.status == Service.SUSPENDED:
        days -= invoicing_config.tolerance  # Catch-up days that were offered before service suspension
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    elif service.expiry:
        expiry = service.expiry + timedelta(days=days)
    else:
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    service.expiry = expiry
    service.status = Service.ACTIVE
    if invoice.is_one_off:
        service.version = Service.FULL
        try:
            support_bundle = SupportBundle.objects.get(
                type=SupportBundle.TECHNICAL,
                channel=SupportBundle.PHONE,
                cost=0)
            token = ''.join([
                random.SystemRandom().choice(string.digits) for i in range(6)
            ])
            support_expiry = now + timedelta(days=support_bundle.duration)
            SupportCode.objects.create(service=service,
                                       token=token,
                                       bundle=support_bundle,
                                       balance=support_bundle.quantity,
                                       expiry=support_expiry)
            logger.debug("Free Support Code created for %s" % service)
        except SupportBundle.DoesNotExist:
            logger.error("Free Support Code not created for %s" % service,
                         exc_info=True)
    service.save()
    mean = tx.wallet
    is_early_payment = False
    if service.app.slug == 'kakocase' or service.app.slug == 'webnode':
        if invoice.due_date <= now.date():
            is_early_payment = True
        refill_tsunami_messaging_bundle(service, is_early_payment)
    share_payment_and_set_stats(invoice, total_months, mean, tx)
    member = service.member
    vendor = service.retailer
    vendor_is_dara = vendor and vendor.app.slug == DARAJA
    if vendor and not vendor_is_dara:
        add_database_to_settings(vendor.database)
        sudo_group = Group.objects.using(vendor.database).get(name=SUDO)
    else:
        vendor = ikwen_service
        sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor,
              PAYMENT_CONFIRMATION,
              member=member,
              object_id=invoice.id)
    add_event(vendor,
              PAYMENT_CONFIRMATION,
              group_id=sudo_group.id,
              object_id=invoice.id)

    try:
        invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
    except:
        invoice_pdf_file = None

    if member.email:
        activate(member.language)
        invoice_url = ikwen_service.url + reverse('billing:invoice_detail',
                                                  args=(invoice.id, ))
        subject, message, sms_text = get_payment_confirmation_message(
            payment, member)
        html_content = get_mail_content(
            subject,
            message,
            service=vendor,
            template_name='billing/mails/notice.html',
            extra_context={
                'member_name': member.first_name,
                'invoice': invoice,
                'cta': _("View invoice"),
                'invoice_url': invoice_url,
                'early_payment': is_early_payment
            })
        sender = '%s <no-reply@%s>' % (vendor.config.company_name,
                                       ikwen_service.domain)
        msg = XEmailMessage(subject, html_content, sender, [member.email])
        if vendor != ikwen_service and not vendor_is_dara:
            msg.service = vendor
        if invoice_pdf_file:
            msg.attach_file(invoice_pdf_file)
        msg.content_subtype = "html"
        if getattr(settings, 'UNIT_TESTING', False):
            msg.send()
        else:
            Thread(target=lambda m: m.send(), args=(msg, )).start()
    return HttpResponse("Notification received")
Esempio n. 3
0
def notify_cashout_and_reset_counters(request, transaction, *args, **kwargs):
    """
    Notifies IAO that request to cashout completed successfully and resets wallet balance accordingly
    :param request:
    :param transaction: MoMoTransaction object used to process this operation
    :return:
    """
    cashout_request = CashOutRequest.objects.using('wallets').get(
        pk=transaction.object_id)
    cashout_request.status = CashOutRequest.PAID
    cashout_request.reference = transaction.processor_tx_id
    charges = cashout_request.amount * cashout_request.rate / 100
    cashout_request.amount_paid = cashout_request.amount * (
        100 - cashout_request.rate) / 100
    cashout_request.save()
    weblet = Service.objects.using(UMBRELLA).get(pk=transaction.service_id)
    wallet = OperatorWallet.objects.using('wallets').get(
        nonrel_id=weblet.id, provider=transaction.wallet)
    method = CashOutMethod.objects.using(UMBRELLA).get(slug=transaction.wallet)
    address = CashOutAddress.objects.using(UMBRELLA).get(service=weblet,
                                                         method=method)
    with db_transaction.atomic(using='wallets'):
        queryset = MoMoTransaction.objects.using('wallets') \
            .filter(created_on__gt=cashout_request.paid_on, type=MoMoTransaction.CASH_OUT,
                    status=MoMoTransaction.SUCCESS, wallet=cashout_request.provider)
        iao = weblet.member
        if weblet.app.slug == DARAJA:
            dara = Dara.objects.get(member=iao)
            queryset = queryset.filter(dara_id=dara.id)
            if queryset.count() > 0:
                aggr = queryset.aggregate(Sum('dara_fees'))
                amount_successful = aggr['dara_fees__sum']
            else:
                amount_successful = 0
        else:
            queryset = queryset.filter(service_id=weblet.id)
            if queryset.count() > 0:
                aggr = queryset.aggregate(Sum('amount'))
                aggr_fees = queryset.aggregate(Sum('fees'))
                aggr_dara_fees = queryset.aggregate(Sum('dara_fees'))
                amount_successful = aggr['amount__sum'] - aggr_fees[
                    'fees__sum'] - aggr_dara_fees['dara_fees__sum']
            else:
                amount_successful = 0
        wallet.balance = amount_successful
        wallet.save(using='wallets')
        if getattr(settings, 'TESTING', False):
            IKWEN_SERVICE_ID = getattr(settings, 'IKWEN_ID')
            ikwen_service = Service.objects.using(UMBRELLA).get(
                pk=IKWEN_SERVICE_ID)
        else:
            from ikwen.conf.settings import IKWEN_SERVICE_ID
            ikwen_service = Service.objects.using(UMBRELLA).get(
                pk=IKWEN_SERVICE_ID)
        sender = 'ikwen <*****@*****.**>'
        event_originator = ikwen_service
        add_event(event_originator,
                  CASH_OUT_REQUEST_PAID,
                  member=iao,
                  object_id=cashout_request.id)

        subject = _("Money transfer confirmation")
        html_content = get_mail_content(
            subject,
            '',
            template_name='cashout/mails/payment_notice.html',
            extra_context={
                'cash_out_request': cashout_request,
                'charges': charges,
                'weblet': weblet,
                'address': address,
                'service': event_originator
            })
        msg = XEmailMessage(subject, html_content, sender, [iao.email])
        msg.service = ikwen_service
        msg.bcc = ['*****@*****.**', '*****@*****.**']
        msg.content_subtype = "html"
        Thread(target=lambda m: m.send(), args=(msg, )).start()

        set_counters(ikwen_service)
        increment_history_field(ikwen_service, 'cash_out_history',
                                cashout_request.amount)
        increment_history_field(ikwen_service, 'cash_out_count_history')
Esempio n. 4
0
def send_expiry_reminders():
    """
    This cron task simply sends the Invoice *invoicing_gap* days before Subscription *expiry*
    """
    ikwen_service = get_service_instance()
    now = datetime.now()
    invoicing_config = InvoicingConfig.objects.all()[0]
    connection = mail.get_connection()
    try:
        connection.open()
    except:
        logger.error(u"Connexion error", exc_info=True)

    reminder_date_time = now + timedelta(days=invoicing_config.gap)

    for invoicing_config in InvoicingConfig.objects.exclude(
            service=ikwen_service):
        service = invoicing_config.service
        if service.status != Service.ACTIVE or invoicing_config.pull_invoice:
            continue
        db = service.database
        add_database(db)
        config = service.basic_config
        subscription_qs = Subscription.objects.using(db)\
            .selected_related('member, product').filter(status=Subscription.ACTIVE,
                                                        monthly_cost__gt=0, expiry=reminder_date_time.date())
        count, total_amount = 0, 0
        for subscription in subscription_qs:
            member = subscription.member
            number = get_next_invoice_number()
            months_count = get_billing_cycle_months_count(
                subscription.billing_cycle)
            amount = subscription.monthly_cost * months_count

            path_before = getattr(settings, 'BILLING_BEFORE_NEW_INVOICE', None)
            if path_before:
                before_new_invoice = import_by_path(path_before)
                val = before_new_invoice(subscription)
                if val is not None:  # Returning a not None value cancels the generation of a new Invoice for this Service
                    continue

            short_description = subscription.product.short_description
            item = InvoiceItem(label=_('Subscription'), amount=amount)
            entry = InvoiceEntry(item=item,
                                 short_description=short_description,
                                 quantity=months_count,
                                 total=amount)
            invoice = Invoice.objects.create(member=member,
                                             subscription=subscription,
                                             amount=amount,
                                             number=number,
                                             due_date=subscription.expiry,
                                             months_count=months_count,
                                             entries=[entry])
            count += 1
            total_amount += amount

            subject, message, sms_text = get_invoice_generated_message(invoice)
            balance, update = Balance.objects.using(
                WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
            if member.email:
                if 0 < balance.mail_count < LOW_MAIL_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.mail_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                else:
                    invoice_url = service.url + reverse(
                        'billing:invoice_detail', args=(invoice.id, ))
                    html_content = get_mail_content(
                        subject,
                        message,
                        service=service,
                        template_name='billing/mails/notice.html',
                        extra_context={
                            'invoice_url': invoice_url,
                            'cta': _("Pay now"),
                            'currency': config.currency_symbol
                        })
                    # Sender is simulated as being no-reply@company_name_slug.com to avoid the mail
                    # to be delivered to Spams because of origin check.
                    sender = '%s <no-reply@%s>' % (config.company_name,
                                                   service.domain)
                    msg = XEmailMessage(subject, html_content, sender,
                                        [member.email])
                    msg.content_subtype = "html"
                    msg.service = service
                    invoice.last_reminder = timezone.now()
                    try:
                        with transaction.atomic(using=WALLETS_DB_ALIAS):
                            if msg.send():
                                balance.mail_count -= 1
                                balance.save()
                                logger.debug(
                                    "1st Invoice reminder for %s sent to %s" %
                                    (subscription, member.email))
                            else:
                                logger.error(
                                    u"Invoice #%s generated but mail not sent to %s"
                                    % (number, member.email),
                                    exc_info=True)
                    except:
                        logger.error(u"Connexion error on Invoice #%s to %s" %
                                     (number, member.email),
                                     exc_info=True)

            if sms_text and member.phone:
                if 0 < balance.sms_count < LOW_SMS_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.sms_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                    continue
                try:
                    with transaction.atomic(using=WALLETS_DB_ALIAS):
                        balance.sms_count -= 1
                        balance.save()
                        phone = member.phone if len(
                            member.phone) > 9 else '237' + member.phone
                        send_sms(phone, sms_text, fail_silently=False)
                except:
                    logger.error(u"SMS for invoice #%s not sent to %s" %
                                 (number, member.email),
                                 exc_info=True)

            path_after = getattr(settings, 'BILLING_AFTER_NEW_INVOICE', None)
            if path_after:
                after_new_invoice = import_by_path(path_after)
                after_new_invoice(invoice)

        if count > 0:
            report = SendingReport.objects.using(db).create(
                count=count, total_amount=total_amount)
            sudo_group = Group.objects.using(db).get(name=SUDO)
            add_event(ikwen_service,
                      INVOICES_SENT_EVENT,
                      group_id=sudo_group.id,
                      object_id=report.id)
    try:
        connection.close()
    except:
        pass
Esempio n. 5
0
def suspend_subscriptions():
    """
    This cron task shuts down service and sends notice of Service suspension
    for Invoices which tolerance is exceeded.
    """
    ikwen_service = get_service_instance()
    now = datetime.now()
    connection = mail.get_connection()
    try:
        connection.open()
    except:
        logger.error(u"Connexion error", exc_info=True)

    for invoicing_config in InvoicingConfig.objects.all():
        service = invoicing_config.service
        if service.status != Service.ACTIVE:
            continue
        config = service.basic_config
        db = service.database
        add_database(db)
        deadline = now - timedelta(days=invoicing_config.tolerance)
        invoice_qs = Invoice.objects.using(db).select_related('subscription')\
            .filter(due_date__lte=deadline, status=Invoice.OVERDUE)
        count, total_amount = 0, 0
        for invoice in invoice_qs:
            due_date = invoice.due_date
            due_datetime = datetime(due_date.year, due_date.month,
                                    due_date.day)
            diff = now - due_datetime
            subscription = invoice.subscription
            tolerance = subscription.tolerance
            if diff.days < tolerance:
                continue
            invoice.status = Invoice.EXCEEDED
            invoice.save()
            count += 1
            total_amount += invoice.amount
            subscription.status = Subscription.SUSPENDED
            subscription.save()
            member = subscription.member
            add_event(service,
                      SERVICE_SUSPENDED_EVENT,
                      member=member,
                      object_id=invoice.id)
            subject, message, sms_text = get_service_suspension_message(
                invoice)
            balance, update = Balance.objects.using(
                WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
            if member.email:
                if 0 < balance.mail_count < LOW_MAIL_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.mail_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                else:
                    invoice_url = service.url + reverse(
                        'billing:invoice_detail', args=(invoice.id, ))
                    html_content = get_mail_content(
                        subject,
                        message,
                        service=service,
                        template_name='billing/mails/notice.html',
                        extra_context={
                            'member_name': member.first_name,
                            'invoice': invoice,
                            'invoice_url': invoice_url,
                            'cta': _("Pay now"),
                            'currency': config.currency_symbol
                        })
                    # Sender is simulated as being no-reply@company_name_slug.com to avoid the mail
                    # to be delivered to Spams because of origin check.
                    sender = '%s <no-reply@%s>' % (config.company_name,
                                                   service.domain)
                    msg = XEmailMessage(subject, html_content, sender,
                                        [member.email])
                    msg.service = service
                    msg.content_subtype = "html"
                    try:
                        with transaction.atomic(using=WALLETS_DB_ALIAS):
                            if msg.send():
                                balance.mail_count -= 1
                                balance.save()
                            else:
                                logger.error(
                                    u"Notice of suspension for Invoice #%s not sent to %s"
                                    % (invoice.number, member.email),
                                    exc_info=True)
                    except:
                        print "Sending mail to %s failed" % member.email
                        logger.error(u"Connexion error on Invoice #%s to %s" %
                                     (invoice.number, member.email),
                                     exc_info=True)

            if sms_text and member.phone:
                if 0 < balance.sms_count < LOW_SMS_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.sms_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                    continue
                try:
                    with transaction.atomic(using=WALLETS_DB_ALIAS):
                        balance.sms_count -= 1
                        balance.save()
                        phone = member.phone if len(
                            member.phone) > 9 else '237' + member.phone
                        send_sms(phone, sms_text, fail_silently=False)
                except:
                    logger.error(
                        u"SMS overdue notice for invoice #%s not sent to %s" %
                        (invoice.number, member.phone),
                        exc_info=True)

        if count > 0:
            report = SendingReport.objects.using(db).create(
                count=count, total_amount=total_amount)
            sudo_group = Group.objects.using(db).get(name=SUDO)
            add_event(ikwen_service,
                      SUSPENSION_NOTICES_SENT_EVENT,
                      group_id=sudo_group.id,
                      object_id=report.id)

    try:
        connection.close()
    except:
        pass
Esempio n. 6
0
def send_invoice_overdue_notices():
    """
    This cron task sends notice of Invoice overdue
    """
    ikwen_service = get_service_instance()
    now = datetime.now()
    connection = mail.get_connection()
    try:
        connection.open()
    except:
        logger.error(u"Connexion error", exc_info=True)

    for invoicing_config in InvoicingConfig.objects.exclude(
            service=ikwen_service):
        service = invoicing_config.service
        if service.status != Service.ACTIVE:
            continue
        config = service.basic_config
        db = service.database
        add_database(db)
        invoice_qs = Invoice.objects.using(db).select_related('subscription')\
            .filter(Q(status=Invoice.PENDING) | Q(status=Invoice.OVERDUE),
                    due_date__lt=now, overdue_notices_sent__lt=3)
        count, total_amount = 0, 0
        for invoice in invoice_qs:
            if invoice.last_overdue_notice:
                diff = now - invoice.last_overdue_notice
            else:
                invoice.status = Invoice.OVERDUE
                invoice.save()
            if invoice.last_overdue_notice and diff.days != invoicing_config.overdue_delay:
                continue
            count += 1
            total_amount += invoice.amount
            member = invoice.subscription.member
            add_event(service,
                      OVERDUE_NOTICE_EVENT,
                      member=member,
                      object_id=invoice.id)
            subject, message, sms_text = get_invoice_overdue_message(invoice)
            balance, update = Balance.objects.using(
                WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
            if member.email:
                if 0 < balance.mail_count < LOW_MAIL_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.mail_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                else:
                    invoice_url = 'http://ikwen.com' + reverse(
                        'billing:invoice_detail', args=(invoice.id, ))
                    html_content = get_mail_content(
                        subject,
                        message,
                        service=service,
                        template_name='billing/mails/notice.html',
                        extra_context={
                            'member_name': member.first_name,
                            'invoice': invoice,
                            'invoice_url': invoice_url,
                            'cta': _("Pay now"),
                            'currency': config.currency_symbol
                        })
                    # Sender is simulated as being no-reply@company_name_slug.com to avoid the mail
                    # to be delivered to Spams because of origin check.
                    sender = '%s <no-reply@%s>' % (config.company_name,
                                                   service.domain)
                    msg = XEmailMessage(subject, html_content, sender,
                                        [member.email])
                    msg.service = service
                    msg.content_subtype = "html"
                    invoice.last_overdue_notice = timezone.now()
                    try:
                        with transaction.atomic(using=WALLETS_DB_ALIAS):
                            if msg.send():
                                invoice.overdue_notices_sent += 1
                                balance.mail_count -= 1
                                balance.save()
                            else:
                                logger.error(
                                    u"Overdue notice for Invoice #%s not sent to %s"
                                    % (invoice.number, member.email),
                                    exc_info=True)
                    except:
                        logger.error(u"Connexion error on Invoice #%s to %s" %
                                     (invoice.number, member.email),
                                     exc_info=True)
                    invoice.save()

            if sms_text and member.phone:
                if 0 < balance.sms_count < LOW_SMS_LIMIT:
                    notify_for_low_messaging_credit(service, balance)
                if balance.sms_count <= 0 and not getattr(
                        settings, 'UNIT_TESTING', False):
                    notify_for_empty_messaging_credit(service, balance)
                    continue
                try:
                    with transaction.atomic(using=WALLETS_DB_ALIAS):
                        balance.sms_count -= 1
                        balance.save()
                        phone = member.phone if len(
                            member.phone) > 9 else '237' + member.phone
                        send_sms(phone, sms_text, fail_silently=False)
                except:
                    logger.error(
                        u"SMS overdue notice for invoice #%s not sent to %s" %
                        (invoice.number, member.phone),
                        exc_info=True)
        if count > 0:
            report = SendingReport.objects.using(db).create(
                count=count, total_amount=total_amount)
            sudo_group = Group.objects.using(db).get(name=SUDO)
            add_event(ikwen_service,
                      OVERDUE_NOTICES_SENT_EVENT,
                      group_id=sudo_group.id,
                      object_id=report.id)

    try:
        connection.close()
    except:
        pass