Example #1
0
def product_do_checkout(request, *args, **kwargs):
    from echo.models import Balance
    from echo.utils import LOW_MAIL_LIMIT, notify_for_low_messaging_credit, notify_for_empty_messaging_credit
    tx = kwargs['tx']
    invoice = Invoice.objects.get(pk=tx.object_id)
    member = invoice.member
    subscription = invoice.subscription
    subscription.status = Subscription.ACTIVE
    subscription.save()
    invoice.status = Invoice.PAID
    invoice.save()
    payment = Payment.objects.create(invoice=invoice,
                                     method=Payment.MOBILE_MONEY,
                                     amount=invoice.amount,
                                     processor_tx_id=tx.processor_tx_id)
    share_payment_and_set_stats(invoice, payment_mean_slug=tx.wallet)
    service = get_service_instance()
    config = service.config

    balance, update = Balance.objects.using(WALLETS_DB_ALIAS).get_or_create(
        service_id=service.id)
    if member and 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, ))
            subject, message, sms_text = get_payment_confirmation_message(
                payment, member)
            html_content = get_mail_content(
                subject,
                message,
                template_name='billing/mails/notice.html',
                extra_context={
                    'member_name': member.first_name,
                    'invoice': invoice,
                    'cta': _("View invoice"),
                    'invoice_url': invoice_url
                })
            sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
            msg = EmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            Thread(target=lambda m: m.send(), args=(msg, )).start()
    messages.success(request,
                     _("Successful payment. Your subscription is now active."))
    return HttpResponseRedirect(request.session['return_url'])
Example #2
0
def rerun_complete_revivals(debug=False):
    """
    Re-run Revivals with status = COMPLETE to keep users engaged
    """
    t0 = datetime.now()
    total_revival, total_mail = 0, 0
    three_days_ago = timezone.now() - timedelta(days=3)
    for revival in Revival.objects.select_related('service').filter(
            status=COMPLETE, is_active=True):
        try:
            refreshed = Revival.objects.get(pk=revival.id)
            if refreshed.is_running:
                continue
            refreshed.is_running = True
            refreshed.save()
            total_revival += 1
        except Revival.DoesNotExist:
            continue

        try:
            mail_renderer = import_by_path(revival.mail_renderer)
            kwargs = {}
            if revival.get_kwargs:
                get_kwargs = import_by_path(revival.get_kwargs)
                kwargs = get_kwargs(revival)
        except:
            revival.is_running = False
            revival.save()
            logger.error("Error when starting revival %s for %s" %
                         (revival.mail_renderer, revival.service),
                         exc_info=True)
            continue

        service = revival.service
        db = revival.service.database
        add_database(db)
        balance = Balance.objects.using(WALLETS_DB_ALIAS).get(
            service_id=service.id)
        if balance.mail_count == 0:
            revival.is_running = False
            revival.save()
            try:
                notify_for_empty_messaging_credit(service, balance)
            except:
                logger.error(
                    "Failed to notify %s for empty messaging credit." %
                    service,
                    exc_info=True)
            continue
        if 0 < balance.mail_count < LOW_MAIL_LIMIT:
            try:
                notify_for_low_messaging_credit(service, balance)
            except:
                logger.error("Failed to notify %s for low messaging credit." %
                             service,
                             exc_info=True)
        tk = revival.model_name.split('.')
        model = get_model(tk[0], tk[1])
        try:
            obj = model._default_manager.using(db).get(pk=revival.object_id)
        except ObjectDoesNotExist:
            revival.is_running = False
            revival.save()
            continue
        try:
            profile_tag = ProfileTag.objects.using(db).get(
                pk=revival.profile_tag_id)
        except:
            revival.is_running = False
            revival.save()
            continue

        set_counters_many(profile_tag)
        revival_local = Revival.objects.using(db).get(pk=revival.id)

        target_queryset = revival_local.target_set.select_related(
            'member').filter(revived_on__lte=three_days_ago,
                             revival_count__lt=MAX_AUTO_REWARDS)
        if target_queryset.count() == 0:
            revival.is_running = False
            revival.save()
            continue
        revival.run_on = timezone.now()
        revival.status = STARTED
        revival.save()
        connection = mail.get_connection()
        try:
            connection.open()
        except:
            revival.is_running = False
            revival.save()
            logger.error(u"Connexion error", exc_info=True)
            continue

        logger.debug("Running rerun_complete_revivals() %s for %s" %
                     (revival.mail_renderer, revival.service))
        for target in target_queryset.order_by('updated_on')[:MAX_BATCH_SEND]:
            if not debug and balance.mail_count == 0:
                revival.is_running = False
                revival.save()
                try:
                    notify_for_empty_messaging_credit(service, balance)
                except:
                    logger.error(
                        "Failed to notify %s for empty messaging credit." %
                        service,
                        exc_info=True)
                break
            member = target.member
            if debug and not member.is_superuser:
                continue
            if member.language:
                activate(member.language)
            else:
                activate('en')

            if getattr(settings, 'UNIT_TESTING', False):
                sender, subject, html_content = mail_renderer(
                    target, obj, revival, **kwargs)
            else:
                try:
                    sender, subject, html_content = mail_renderer(
                        target, obj, revival, **kwargs)
                except:
                    logger.error(
                        "Could not render mail for member %s, Revival %s, Obj: %s"
                        % (member.email, revival.mail_renderer, str(obj)),
                        exc_info=True)
                    continue

            if not html_content:
                continue
            if debug:
                subject = 'Test remind - ' + subject
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            msg.type = XEmailObject.REVIVAL
            try:
                with transaction.atomic(using=WALLETS_DB_ALIAS):
                    if not debug:
                        balance.mail_count -= 1
                        balance.save()
                    if msg.send():
                        target.revival_count += 1
                        target.revived_on = t0
                        target.save()
                        total_mail += 1
                        increment_history_field(profile_tag,
                                                'smart_revival_history')
                    else:
                        logger.error("Member %s not notified for Content %s" %
                                     (member.email, str(obj)),
                                     exc_info=True)
            except:
                logger.error("Member %s not notified for Content %s" %
                             (member.email, str(obj)),
                             exc_info=True)

        revival.is_running = False
        revival.progress += 1
        revival.save()

        try:
            connection.close()
        except:
            revival.is_running = False
            revival.save()

    diff = datetime.now() - t0
    logger.debug(
        "rerun_complete_revivals() run %d revivals. %d mails sent in %s" %
        (total_revival, total_mail, diff))
Example #3
0
def notify_profiles(debug=False):
    """
    Cron job that revive users by mail. Must be configured
    to run with a settings file having 'umbrella' as default database.
    :return:
    """
    t0 = datetime.now()
    seven_hours_ago = t0 - timedelta(hours=7)
    total_revival, total_mail = 0, 0
    for revival in Revival.objects.select_related('service').exclude(
            status=COMPLETE, is_active=False):
        try:
            refreshed = Revival.objects.get(pk=revival.id)
            if refreshed.is_running:
                continue
            refreshed.is_running = True
            refreshed.save()
            total_revival += 1
        except Revival.DoesNotExist:
            continue

        try:
            mail_renderer = import_by_path(revival.mail_renderer)
            kwargs = {}
            if revival.get_kwargs:
                get_kwargs = import_by_path(revival.get_kwargs)
                kwargs = get_kwargs(revival)
        except:
            revival.is_running = False
            revival.save()
            logger.error("Error when starting revival %s for %s" %
                         (revival.mail_renderer, revival.service),
                         exc_info=True)
            continue

        service = revival.service
        db = service.database
        add_database(db)
        balance = Balance.objects.using(WALLETS_DB_ALIAS).get(
            service_id=service.id)
        if balance.mail_count == 0:
            revival.is_running = False
            revival.save()
            try:
                notify_for_empty_messaging_credit(service, balance)
            except:
                logger.error(
                    "Failed to notify %s for empty messaging credit." %
                    service,
                    exc_info=True)
            continue
        if 0 < balance.mail_count < LOW_MAIL_LIMIT:
            try:
                notify_for_low_messaging_credit(service, balance)
            except:
                logger.error("Failed to notify %s for low messaging credit." %
                             service,
                             exc_info=True)
        tk = revival.model_name.split('.')
        model = get_model(tk[0], tk[1])
        try:
            obj = model._default_manager.using(db).get(pk=revival.object_id)
        except ObjectDoesNotExist:
            revival.is_running = False
            revival.save()
            continue
        try:
            profile_tag = ProfileTag.objects.using(db).get(
                pk=revival.profile_tag_id)
        except:
            revival.is_running = False
            revival.save()
            continue

        if revival.status != PENDING:
            revival.is_running = False
            revival.save()
            continue

        set_counters(profile_tag)
        revival_local = Revival.objects.using(db).get(pk=revival.id)
        if debug:
            member_queryset = Member.objects.using(db).filter(
                is_superuser=True)
        else:
            member_queryset = Member.objects.using(db).filter(
                date_joined__lte=seven_hours_ago)
        total = member_queryset.count()
        chunks = total / 500 + 1
        target_count = 0
        for i in range(chunks):
            start = i * 500
            finish = (i + 1) * 500
            for member in member_queryset.order_by(
                    'date_joined')[start:finish]:
                try:
                    profile = MemberProfile.objects.using(db).get(
                        member=member)
                except MemberProfile.DoesNotExist:
                    ref_tag = ProfileTag.objects.using(db).get(slug=REFERRAL)
                    profile = MemberProfile.objects.using(db).create(
                        member=member, tag_fk_list=[ref_tag.id])
                if revival.profile_tag_id in profile.tag_fk_list:
                    if debug:
                        tag = ProfileTag.objects.using(db).get(
                            pk=revival.profile_tag_id)
                        print "Profiles matching on %s for member %s" % (
                            tag, member)
                    if member.email:
                        Target.objects.using(db).get_or_create(
                            revival=revival_local, member=member)
                        target_count += 1

        if target_count == 0:
            revival.is_running = False
            revival.save()
            continue

        revival.run_on = datetime.now()
        revival.status = STARTED
        revival.total = revival_local.target_set.all().count()
        revival.save()

        connection = mail.get_connection()
        try:
            connection.open()
        except:
            revival.is_running = False
            revival.save()
            logger.error(u"Connexion error", exc_info=True)
            continue

        logger.debug("Running notify_profiles() %s for %s" %
                     (revival.mail_renderer, revival.service))
        for target in revival_local.target_set.select_related('member').filter(
                notified=False)[:MAX_BATCH_SEND]:
            if not debug and balance.mail_count == 0:
                revival.is_running = False
                revival.save()
                try:
                    notify_for_empty_messaging_credit(service, balance)
                except:
                    logger.error(
                        "Failed to notify %s for empty messaging credit." %
                        service,
                        exc_info=True)
                break
            member = target.member
            if member.language:
                activate(member.language)
            else:
                activate('en')

            if getattr(settings, 'UNIT_TESTING', False):
                sender, subject, html_content = mail_renderer(
                    target, obj, revival, **kwargs)
            else:
                try:
                    sender, subject, html_content = mail_renderer(
                        target, obj, revival, **kwargs)
                except:
                    logger.error(
                        "Could not render mail for member %s, Revival %s, Obj: %s"
                        % (member.email, revival.mail_renderer, str(obj)),
                        exc_info=True)
                    continue

            if not html_content:
                continue
            if debug:
                subject = 'Test - ' + subject
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            msg.type = XEmailObject.REVIVAL
            try:
                with transaction.atomic(using=WALLETS_DB_ALIAS):
                    if not debug:
                        balance.mail_count -= 1
                        balance.save()
                    if msg.send():
                        target.revival_count += 1
                        target.notified = True
                        target.revived_on = t0
                        target.save()
                        total_mail += 1
                        increment_history_field(profile_tag,
                                                'smart_revival_history')
                    else:
                        logger.error("Member %s not notified for Content %s" %
                                     (member.email, str(obj)),
                                     exc_info=True)
            except:
                logger.error("Member %s not notified for Content %s" %
                             (member.email, str(obj)),
                             exc_info=True)
            revival.progress += 1
            revival.save()

        revival.is_running = False
        if revival.progress > 0 and revival.progress >= revival.total:
            revival.status = COMPLETE
        revival.save()

        try:
            connection.close()
        except:
            revival.is_running = False
            revival.save()

    diff = datetime.now() - t0
    logger.debug("notify_profiles() run %d revivals. %d mails sent in %s" %
                 (total_revival, total_mail, diff))
Example #4
0
def confirm_invoice_payment(request, *args, **kwargs):
    """
    This function has no URL associated with it.
    It serves as ikwen setting "MOMO_AFTER_CHECKOUT"
    """
    from echo.models import Balance
    from echo.utils import LOW_MAIL_LIMIT, notify_for_low_messaging_credit, notify_for_empty_messaging_credit
    tx = kwargs.get('transaction')
    now = datetime.now()
    service = get_service_instance()
    config = service.config
    invoicing_config = get_invoicing_config_instance()
    invoice_id = request.session['object_id']
    amount = request.session['amount']
    invoice = Invoice.objects.select_related('subscription').get(pk=invoice_id)
    invoice.paid += amount
    invoice.status = Invoice.PAID
    if invoicing_config.processing_fees_on_customer:
        invoice.processing_fees = config.ikwen_share_fixed
    invoice.save()
    payment = Payment.objects.create(invoice=invoice, method=Payment.MOBILE_MONEY,
                                     amount=amount, processor_tx_id=tx.processor_tx_id)
    subscription = invoice.subscription
    if invoicing_config.separate_billing_cycle:
        extra_months = request.session['extra_months']
        total_months = invoice.months_count + extra_months
        days = get_days_count(total_months)
    else:
        extra_months = 0
        days = invoice.subscription.product.duration
        total_months = None
    if subscription.status == Service.SUSPENDED:
        invoicing_config = get_invoicing_config_instance()
        days -= invoicing_config.tolerance  # Catch-up days that were offered before service suspension
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    elif subscription.expiry:
        expiry = subscription.expiry + timedelta(days=days)
    else:
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    subscription.expiry = expiry
    subscription.status = Service.ACTIVE
    subscription.save()
    mean = request.session['mean']
    share_payment_and_set_stats(invoice, total_months, mean)
    member = request.user
    sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(service, PAYMENT_CONFIRMATION, member=member, object_id=invoice.id)
    add_event(service, PAYMENT_CONFIRMATION, group_id=sudo_group.id, object_id=invoice.id)

    if invoicing_config.return_url:
        params = {'reference_id': subscription.reference_id, 'invoice_number': invoice.number,
                  'amount_paid': amount, 'processor_tx_id': tx.processor_tx_id, 'extra_months': extra_months}
        Thread(target=notify_event, args=(service, invoicing_config.return_url, params)).start()

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

    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:
            notify_for_empty_messaging_credit(service, balance)
        else:
            try:
                currency = Currency.active.default().symbol
            except:
                currency = config.currency_code
            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, template_name='billing/mails/notice.html',
                                            extra_context={'member_name': member.first_name, 'invoice': invoice,
                                                           'cta': _("View invoice"), 'invoice_url': invoice_url,
                                                           'currency': currency})
            sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            if invoice_pdf_file:
                msg.attach_file(invoice_pdf_file)
            balance.mail_count -= 1
            balance.save()
            Thread(target=lambda m: m.send(), args=(msg,)).start()
    return HttpResponseRedirect(request.session['return_url'])
Example #5
0
    def cash_in(self, invoice, request):
        if not request.user.has_perm('billing.ik_cash_in'):
            return HttpResponse(
                json.dumps({'error': "You're not allowed here"}))
        service = get_service_instance()
        config = service.config
        invoicing_config = get_invoicing_config_instance()
        if invoice.status == Invoice.PAID:
            return HttpResponse(json.dumps({'error': "Invoice already paid"}))
        amount = request.GET.get('amount', invoice.amount)
        try:
            amount = float(amount)
            if amount <= 0:
                raise ValueError()
        except ValueError:
            return HttpResponse(json.dumps({'error': "Invalid amount"}))
        member = invoice.member
        payment = Payment.objects.create(invoice=invoice,
                                         amount=amount,
                                         method=Payment.CASH,
                                         cashier=request.user)
        response = {'success': True, 'payment': payment.to_dict()}
        try:
            aggr = Payment.objects.filter(invoice=invoice).aggregate(
                Sum('amount'))
            amount_paid = aggr['amount__sum']
        except IndexError:
            amount_paid = 0

        if invoicing_config.return_url:
            try:
                subscription = invoice.subscription
                extra_months = request.GET.get('extra_months', 0)
                params = {
                    'reference_id': subscription.reference_id,
                    'invoice_number': invoice.number,
                    'amount_paid': amount,
                    'extra_months': extra_months
                }
                Thread(target=notify_event,
                       args=(service, invoicing_config.return_url,
                             params)).start()
            except:
                notice = "%s: Could not notify endpoint %s after cash in" % (
                    service, invoicing_config.return_url)
                logger.error(notice, exc_info=True)

        total = amount + amount_paid
        invoice.paid += amount
        if total >= invoice.amount:
            invoice.status = Invoice.PAID
            try:
                subscription = invoice.subscription
                subscription.status = Subscription.ACTIVE
                days = get_days_count(invoice.months_count)
                subscription.expiry += timedelta(days=days)
                subscription.save()
            except AttributeError:
                pass
        invoice.save()
        set_counters(service)
        increment_history_field(service, 'turnover_history', amount)
        increment_history_field(service, 'earnings_history', amount)
        increment_history_field(service, 'transaction_earnings_history',
                                amount)
        increment_history_field(service, 'invoice_earnings_history', amount)
        increment_history_field(service, 'transaction_count_history')
        increment_history_field(service, 'invoice_count_history')
        if member.email:
            from echo.models import Balance
            from echo.utils import notify_for_low_messaging_credit, LOW_MAIL_LIMIT, notify_for_empty_messaging_credit
            balance = Balance.objects.using(WALLETS_DB_ALIAS).get(
                service_id=service.id)
            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)
                return HttpResponse(json.dumps(response))
            subject, message, sms = get_payment_confirmation_message(
                payment, member)
            html_content = get_mail_content(
                subject, message, template_name='billing/mails/notice.html')
            sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            try:
                with transaction.atomic(using='wallets'):
                    balance.mail_count -= 1
                    balance.save()
                    Thread(target=lambda m: m.send(), args=(msg, )).start()
            except:
                pass
        return HttpResponse(json.dumps(response))
Example #6
0
 def after_save(self, request, obj, *args, **kwargs):
     object_id = kwargs.get('object_id')
     if object_id:
         return
     number = get_next_invoice_number()
     months_count = get_billing_cycle_months_count(obj.billing_cycle)
     try:
         amount = float(request.POST.get('amount'))
     except:
         amount = obj.monthly_cost * months_count
     product = obj.product
     if product:
         short_description = product.name
     else:
         short_description = request.POST.get('short_description', '---')
     obj.details = short_description
     obj.save()
     invoice_entries = []
     item = InvoiceItem(label=_('Subscription'), amount=amount)
     entry = InvoiceEntry(item=item,
                          short_description=short_description,
                          quantity=months_count,
                          total=amount)
     invoice_entries.append(entry)
     invoice = Invoice.objects.create(number=number,
                                      subscription=obj,
                                      amount=amount,
                                      months_count=months_count,
                                      due_date=obj.expiry,
                                      entries=invoice_entries,
                                      is_one_off=True)
     email = request.POST.get('email')
     member_id = request.POST.get('member_id')
     if member_id:
         member = Member.objects.get(pk=member_id) if member_id else None
     elif email:
         try:
             member = Member.objects.filter(email=email)[0]
         except:
             member = Member.objects.create_user(email,
                                                 DEFAULT_GHOST_PWD,
                                                 email=email,
                                                 is_ghost=True)
     else:
         return
     obj.member = member
     obj.save()
     service = get_service_instance()
     config = service.config
     with transaction.atomic(using=WALLETS_DB_ALIAS):
         from echo.models import Balance
         from echo.utils import notify_for_low_messaging_credit, LOW_MAIL_LIMIT, notify_for_empty_messaging_credit
         balance, update = Balance.objects.using(
             WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
         if 0 < balance.mail_count < LOW_MAIL_LIMIT:
             try:
                 notify_for_low_messaging_credit(service, balance)
             except:
                 logger.error(
                     "Failed to notify %s for low messaging credit." %
                     service,
                     exc_info=True)
         if balance.mail_count == 0 and not getattr(settings,
                                                    'UNIT_TESTING', False):
             try:
                 notify_for_empty_messaging_credit(service, balance)
             except:
                 logger.error(
                     "Failed to notify %s for empty messaging credit." %
                     service,
                     exc_info=True)
             return
         if product:
             subject = _("Your invoice for subscription to %s" %
                         product.name)
         else:
             if short_description != '---':
                 subject = _("Your invoice for " + short_description)
             else:
                 subject = _("Your invoice for subscription")
         try:
             currency = currencies(request)['CURRENCY'].symbol
         except:
             currency = config.currency_symbol
         invoice_url = service.url + reverse('billing:invoice_detail',
                                             args=(invoice.id, ))
         html_content = get_mail_content(
             subject,
             template_name='billing/mails/notice.html',
             extra_context={
                 'invoice': invoice,
                 'member_name': member.first_name,
                 'invoice_url': invoice_url,
                 'cta': _("Pay now"),
                 'currency': currency
             })
         sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
         msg = XEmailMessage(subject, html_content, sender, [email])
         msg.content_subtype = "html"
         balance.mail_count -= 1
         balance.save()
         if getattr(settings, 'UNIT_TESTING', False):
             msg.send()
         else:
             Thread(target=lambda m: m.send(), args=(msg, )).start()
Example #7
0
def invite_member(service, member):
    sender = '%s <no-reply@%s>' % (service.project_name, service.domain)
    config = service.config
    try:
        invitation_message = config.__getattribute__('invitation_message')
    except AttributeError:
        return
    template_name = 'revival/mails/suggest_create_account.html'
    kwargs = get_join_reward_pack_list(service=service)
    join_reward_pack_list = kwargs['reward_pack_list']
    if join_reward_pack_list:
        subject = _("Join us on ikwen and earn free coupons." %
                    service.project_name)
        email_type = XEmailObject.REWARDING
    else:
        subject = _("Join our community on ikwen.")
        email_type = XEmailObject.REVIVAL
    if invitation_message or join_reward_pack_list:
        with transaction.atomic(using=WALLETS_DB_ALIAS):
            from echo.models import Balance
            from echo.utils import LOW_MAIL_LIMIT, notify_for_low_messaging_credit, notify_for_empty_messaging_credit
            balance, update = Balance.objects.using(
                WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
            if 0 < balance.mail_count < LOW_MAIL_LIMIT:
                try:
                    notify_for_low_messaging_credit(service, balance)
                except:
                    logger.error(
                        "Failed to notify %s for low messaging credit." %
                        service,
                        exc_info=True)
            if balance.mail_count == 0 and not getattr(settings,
                                                       'UNIT_TESTING', False):
                try:
                    notify_for_empty_messaging_credit(service, balance)
                except:
                    logger.error(
                        "Failed to notify %s for empty messaging credit." %
                        service,
                        exc_info=True)
                return
        invitation_message = invitation_message.replace(
            '$client', member.first_name)
        extra_context = {
            'member_name': member.first_name,
            'join_reward_pack_list': join_reward_pack_list,
            'invitation_message': invitation_message
        }
        try:
            html_content = get_mail_content(subject,
                                            service=service,
                                            template_name=template_name,
                                            extra_context=extra_context)
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            msg.type = email_type
            if not getattr(settings, 'UNIT_TESTING', False):
                balance.mail_count -= 1
            balance.save()
            Thread(target=lambda m: m.send(), args=(msg, )).start()
            notice = "%s: Invitation sent message to member after ghost registration attempt" % service.project_name_slug
            logger.error(notice, exc_info=True)
        except:
            notice = "%s: Failed to send invite message to member after ghost registration attempt" % service.project_name_slug
            logger.error(notice, exc_info=True)
Example #8
0
def notify_profiles(debug=False):
    t0 = datetime.now()
    total_revival, total_mail, total_sms = 0, 0, 0
    logger.debug("Starting cyclic revival")
    today = t0.date()
    queryset = CyclicRevival.objects.select_related('service')\
        .filter(next_run_on=today, hour_of_sending=t0.hour, end_on__gt=today, is_active=True)
    for revival in queryset:
        try:
            refreshed = CyclicRevival.objects.get(pk=revival.id)
            if refreshed.is_running:
                continue
            refreshed.is_running = True
            refreshed.save()
            total_revival += 1
        except CyclicRevival.DoesNotExist:
            continue
        service = revival.service
        db = service.database
        add_database(db)
        balance = Balance.objects.using(WALLETS_DB_ALIAS).get(
            service_id=service.id)
        if balance.mail_count == 0 and balance.sms_count == 0:
            try:
                notify_for_empty_messaging_credit(service, balance)
            except:
                revival.is_running = False
                revival.save()
                logger.error(
                    "Failed to notify %s for empty messaging credit." %
                    service,
                    exc_info=True)
            continue
        if 0 < balance.mail_count < LOW_MAIL_LIMIT or 0 < balance.sms_count < LOW_SMS_LIMIT:
            try:
                notify_for_low_messaging_credit(service, balance)
            except:
                revival.is_running = False
                revival.save()
                logger.error("Failed to notify %s for low messaging credit." %
                             service,
                             exc_info=True)

        label = get_sms_label(service.config)
        notified_empty_mail_credit = False
        notified_empty_sms_credit = False
        if debug:
            member_queryset = Member.objects.using(db).filter(
                is_superuser=True)
        else:
            member_queryset = Member.objects.using(db).all()
        total = member_queryset.count()
        try:
            profile_tag = ProfileTag.objects.using(db).get(
                pk=revival.profile_tag_id)
        except ProfileTag.DoesNotExist:
            revival.delete()
            continue
        set_counters(profile_tag)

        revival_local = CyclicRevival.objects.using(db).get(pk=revival.id)
        chunks = total / 500 + 1
        for i in range(chunks):
            start = i * 500
            finish = (i + 1) * 500
            for member in member_queryset.order_by(
                    'date_joined')[start:finish]:
                try:
                    profile = MemberProfile.objects.using(db).get(
                        member=member)
                except MemberProfile.DoesNotExist:
                    continue
                match = set(profile.tag_fk_list) & {profile_tag.id}
                if len(match) > 0:
                    if member.email:
                        CyclicTarget.objects.using(db).get_or_create(
                            revival=revival_local, member=member)
        revival.set_next_run_date()

        connection = mail.get_connection()
        try:
            connection.open()
        except:
            logger.error(u"Connexion error", exc_info=True)
            break

        logger.debug("Running revival %s for %s" %
                     (revival.mail_subject, revival.service))
        for target in revival_local.cyclictarget_set.select_related('member'):
            member = target.member
            if member.language:
                activate(member.language)
            else:
                activate('en')
            subject = revival.mail_subject
            message = revival.mail_content.replace('$client',
                                                   member.first_name)
            sender = '%s <no-reply@%s>' % (service.project_name,
                                           service.domain)
            try:
                currency = Currency.objects.using(using=db).get(is_base=True)
            except Currency.DoesNotExist:
                currency = None
            product_list = []
            if service.app.slug == 'kakocase':
                product_list = Product.objects.using(db).filter(
                    pk__in=revival.items_fk_list)
            extra_context = {
                'revival':
                revival,
                'currency':
                currency,
                'media_url':
                getattr(settings, 'CLUSTER_MEDIA_URL') +
                service.project_name_slug + '/',
                'product_list':
                product_list
            }
            try:
                html_content = get_mail_content(
                    subject,
                    message,
                    template_name='revival/mails/default.html',
                    service=service,
                    extra_context=extra_context)
            except:
                logger.error(
                    "Could not render mail for member %s, Cyclic revival on %s"
                    % (member.username, profile_tag),
                    exc_info=True)
                break
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            msg.type = XEmailObject.REVIVAL

            if balance.mail_count == 0 and not notified_empty_mail_credit:
                notify_for_empty_messaging_credit(service, balance)
                notified_empty_mail_credit = True
            else:
                try:
                    with transaction.atomic(using=WALLETS_DB_ALIAS):
                        if not debug:
                            balance.mail_count -= 1
                            balance.save()
                        if msg.send():
                            target.revival_count += 1
                            target.save()
                            total_mail += 1
                            increment_history_field(
                                profile_tag, 'cyclic_revival_mail_history')
                        else:
                            logger.error(
                                "Cyclic revival with subject %s not sent for member %s"
                                % (subject, member.email),
                                exc_info=True)
                except:
                    logger.error(
                        "Critical error in revival %s when processing Mail sending for member %s"
                        % (revival.id, member.email),
                        exc_info=True)
            if revival.sms_text:
                if balance.sms_count == 0 and not notified_empty_sms_credit:
                    notify_for_empty_messaging_credit(service, balance)
                    notified_empty_sms_credit = True
                else:
                    sms_text = revival.sms_text.replace(
                        '$client', member.first_name)
                    page_count = count_pages(sms_text)
                    try:
                        with transaction.atomic(using=WALLETS_DB_ALIAS):
                            balance.sms_count -= page_count
                            balance.save()
                            send_sms(recipient=member.phone,
                                     text=sms_text,
                                     fail_silently=False)
                            total_sms += 1
                            increment_history_field(
                                profile_tag, 'cyclic_revival_sms_history')
                            SMSObject.objects.create(recipient=member.phone,
                                                     text=sms_text,
                                                     label=label)
                    except:
                        logger.error(
                            "Critical error in revival %s when processing SMS sending for member %s"
                            % (revival.id, member.email),
                            exc_info=True)
            if balance.mail_count == 0 and balance.sms_count == 0:
                break
        revival.is_running = False
        revival.save()
        try:
            connection.close()
        except:
            pass
        diff = datetime.now() - t0
        logger.debug("%d revivals run. %d mails and %d SMS sent in %s" %
                     (total_revival, total_mail, total_sms, diff))
Example #9
0
def send_order_confirmation_sms(buyer_name, buyer_phone, order):
    service = get_service_instance()
    config = service.config
    script_url = getattr(settings, 'SMS_API_SCRIPT_URL', config.sms_api_script_url)
    if not script_url:
        return
    details_max_length = 90
    details = order.get_products_as_string()
    if len(details) > details_max_length:
        tokens = details.split(',')
        while len(details) > details_max_length:
            tokens = tokens[:-1]
            details = ','.join(tokens)
        details += ' ...'
    client_text = _("Order successful:\n"
                    "%(details)s\n"
                    "Your RCC is %(rcc)s\n"
                    "Thank you." % {'details': details, 'rcc': order.rcc.upper()})
    iao_text = "Order from %(buyer_name)s:\n" \
               "%(details)s\n" \
               "RCC: %(rcc)s" % {'buyer_name': buyer_name[:20], 'details': details, 'rcc': order.rcc.upper()}

    iao_phones = [phone.strip() for phone in config.notification_phone.split(',') if phone.strip()]
    client_page_count = count_pages(client_text)
    iao_page_count = count_pages(iao_text)
    needed_credit = client_page_count + iao_page_count * len(iao_phones)
    balance, update = Balance.objects.using(WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
    if needed_credit < balance.mail_count < LOW_SMS_LIMIT:
        try:
            notify_for_low_messaging_credit(service, balance)
        except:
            logger.error("Failed to notify %s for low messaging credit." % service, exc_info=True)
    if balance.sms_count < needed_credit:
        try:
            notify_for_empty_messaging_credit(service, balance)
        except:
            logger.error("Failed to notify %s for empty messaging credit." % service, exc_info=True)
        return
    buyer_phone = buyer_phone.strip()
    buyer_phone = slugify(buyer_phone).replace('-', '')
    if buyer_phone and len(buyer_phone) == 9:
        buyer_phone = '237' + buyer_phone  # This works only for Cameroon
    try:
        with transaction.atomic(using=WALLETS_DB_ALIAS):
            balance.sms_count -= client_page_count
            balance.save()
            send_sms(buyer_phone, client_text, script_url=script_url, fail_silently=False)
    except:
        pass

    for phone in iao_phones:
        phone = slugify(phone).replace('-', '')
        if len(phone) == 9:
            phone = '237' + phone
        try:
            with transaction.atomic(using=WALLETS_DB_ALIAS):
                balance.sms_count -= iao_page_count
                balance.save()
                send_sms(phone, iao_text, script_url=script_url, fail_silently=False)
        except:
            pass
Example #10
0
def pull_invoice(request, *args, **kwargs):
    api_signature = request.POST.get('api_signature')
    try:
        service = Service.objects.get(api_signature=api_signature)
    except:
        notice = "Invalid API Signature."
        response = {'error': notice}
        return HttpResponse(json.dumps(response))

    db = service.database
    add_database(db)
    invoicing_config, update = InvoicingConfig.objects.using(db).get_or_create(
        service=service)
    if not invoicing_config.pull_invoice:
        notice = "Cannot import when not explicitly configured to do so. You must activate " \
                 "'pull_invoice' in your platform configuration for import to work."
        response = {'error': notice}
        return HttpResponse(json.dumps(response))

    lang = request.POST.get('lang', "en")
    activate(lang)
    missing = []
    errors = []
    do_pull = True
    try:
        number = request.POST['invoice_number'].strip()
        try:
            Invoice.objects.using(db).get(number=number)
            errors.append(
                "Invoice with number '%s' already exists. Invoice numbers must be unique."
                % number)
            do_pull = False
        except Invoice.DoesNotExist:
            pass
    except KeyError:
        missing.append('invoice_number')
        do_pull = False
    try:
        reference_id = request.POST['reference_id']
    except KeyError:
        reference_id = None
        missing.append('reference_id')
        do_pull = False
    try:
        amount = request.POST['amount']
        amount = float(amount)
    except KeyError:
        missing.append('amount')
        do_pull = False
    except ValueError:
        errors.append("Invalid amount '%s'. Expected valid float or int.")
        do_pull = False
    try:
        due_date = request.POST['due_date']
        time.strptime(due_date, '%Y-%m-%d')
    except KeyError:
        missing.append('due_date')
        do_pull = False
    except ValueError:
        errors.append(
            "Invalid due_date '%s'. Expected valid date in the format 'YYYY-mm-dd'."
        )
        do_pull = False
    try:
        quantity = request.POST['quantity']
    except KeyError:
        missing.append('quantity')
        do_pull = False
    except ValueError:
        errors.append("Invalid quantity '%s'. Expected valid int.")
        do_pull = False
    quantity_unit = request.POST.get('quantity_unit', _("Month(s)"))
    currency_code = request.POST.get('currency_code', 'XAF')
    if reference_id:
        try:
            subscription = Subscription.objects.using(db).select_related(
                'member', 'product').get(reference_id=reference_id)
        except Subscription.DoesNotExist:
            do_pull = False
            notice = "reference_id '%s' not found." % reference_id
            errors.append(notice)
    if not do_pull:
        response = {'error': '\n'.join(errors)}
        if missing:
            response[
                'missing'] = 'Following parameters are missing: ' + ', '.join(
                    missing)
        return HttpResponse(json.dumps(response))

    product = subscription.product
    if product:
        short_description = product.name
    else:
        short_description = request.POST.get('short_description', '---')
    invoice_entries = []
    item = InvoiceItem(label=_('Subscription'), amount=amount)
    entry = InvoiceEntry(item=item,
                         short_description=short_description,
                         quantity=quantity,
                         quantity_unit=quantity_unit,
                         total=amount)
    invoice_entries.append(entry)
    invoice = Invoice.objects.using(db).create(number=number,
                                               member=subscription.member,
                                               subscription=subscription,
                                               amount=amount,
                                               months_count=quantity,
                                               due_date=due_date,
                                               entries=invoice_entries)
    config = service.config
    member = subscription.member
    if member.email:
        with transaction.atomic(using=WALLETS_DB_ALIAS):
            from echo.models import Balance
            from echo.utils import notify_for_low_messaging_credit, LOW_MAIL_LIMIT, notify_for_empty_messaging_credit
            balance, update = Balance.objects.using(
                WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
            if 0 < balance.mail_count < LOW_MAIL_LIMIT:
                notify_for_low_messaging_credit(service, balance)
            if balance.mail_count <= 0:
                notify_for_empty_messaging_credit(service, balance)
                response = {
                    'success': True,
                    'warning': "Email not set due to empty mail credit"
                }
                return HttpResponse(json.dumps(response))
            subject, message, sms_text = get_invoice_generated_message(invoice)
            try:
                currency = Currency.objects.using(db).get(
                    code=currency_code).symbol
            except:
                try:
                    currency = Currency.active.default().symbol
                except:
                    currency = currency_code

            invoice_url = service.url + reverse('billing:invoice_detail',
                                                args=(invoice.id, ))
            html_content = get_mail_content(
                subject,
                template_name='billing/mails/notice.html',
                service=service,
                extra_context={
                    'invoice': invoice,
                    'member_name': member.first_name,
                    'invoice_url': invoice_url,
                    'cta': _("Pay now"),
                    'currency': currency
                })
            sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
            msg = XEmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            balance.mail_count -= 1
            balance.save()
            if getattr(settings, 'UNIT_TESTING', False):
                msg.send()
            else:
                Thread(target=lambda m: m.send(), args=(msg, )).start()
    response = {'success': True, 'invoice_id': invoice.id}
    return HttpResponse(json.dumps(response))
Example #11
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
Example #12
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
Example #13
0
def send_order_confirmation_email(request,
                                  subject,
                                  buyer_name,
                                  buyer_email,
                                  order,
                                  message=None,
                                  reward_pack_list=None):
    service = get_service_instance()
    coupon_count = 0
    if reward_pack_list:
        template_name = 'shopping/mails/order_notice_with_reward.html'
        for pack in reward_pack_list:
            coupon_count += pack.count
    else:
        template_name = 'shopping/mails/order_notice.html'

    with transaction.atomic(using=WALLETS_DB_ALIAS):
        balance, update = Balance.objects.using(
            WALLETS_DB_ALIAS).get_or_create(service_id=service.id)
        if 0 < balance.mail_count < LOW_MAIL_LIMIT:
            try:
                notify_for_low_messaging_credit(service, balance)
            except:
                logger.error("Failed to notify %s for low messaging credit." %
                             service,
                             exc_info=True)
        if balance.mail_count <= 0 and not getattr(settings, 'UNIT_TESTING',
                                                   False):
            try:
                notify_for_empty_messaging_credit(service, balance)
            except:
                logger.error(
                    "Failed to notify %s for empty messaging credit." %
                    service,
                    exc_info=True)
            return
        try:
            crcy = currencies(request)['CURRENCY']
            html_content = get_mail_content(subject,
                                            template_name=template_name,
                                            extra_context={
                                                'buyer_name':
                                                buyer_name,
                                                'order':
                                                order,
                                                'message':
                                                message,
                                                'IS_BANK':
                                                getattr(
                                                    settings, 'IS_BANK',
                                                    False),
                                                'coupon_count':
                                                coupon_count,
                                                'crcy':
                                                crcy
                                            })
            sender = '%s <no-reply@%s>' % (service.project_name,
                                           service.domain)
            msg = XEmailMessage(subject, html_content, sender, [buyer_email])
            bcc = [
                email.strip()
                for email in service.config.notification_email.split(',')
                if email.strip()
            ]
            delcom = order.delivery_option.company
            if service != delcom:
                db = delcom.database
                add_database(db)
                try:
                    delcom_config = OperatorProfile.objects.using(db).get(
                        service=delcom)
                    bcc += [
                        email.strip() for email in
                        delcom_config.notification_email.split(',')
                        if email.strip()
                    ]
                    bcc.append(delcom.member.email)
                except:
                    pass
            bcc.append(service.member.email)
            msg.bcc = list(set(bcc))
            msg.content_subtype = "html"
            if not getattr(settings, 'UNIT_TESTING', False):
                balance.mail_count -= len(msg.bcc) + 1
            balance.save()
            Thread(target=lambda m: m.send(), args=(msg, )).start()
        except:
            logger.error("%s - Failed to send order confirmation email." %
                         service,
                         exc_info=True)
Example #14
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