Ejemplo n.º 1
0
 def get_context_data(self, **kwargs):
     context = super(ServiceDetail, self).get_context_data(**kwargs)
     invoicing_config = get_invoicing_config_instance(UMBRELLA)
     service_id = kwargs.get('service_id')
     if not service_id:
         service_id = getattr(settings, 'IKWEN_SERVICE_ID')
     srvce = Service.objects.using(UMBRELLA).get(pk=service_id)
     invoice = Invoice.get_last(srvce)
     now = datetime.now()
     if invoice:
         srvce.last_payment = invoice.created_on
     if not srvce.version or srvce.version == Service.FREE:
         srvce.expiry = None
     else:
         srvce.next_invoice_on = srvce.expiry - timedelta(
             days=invoicing_config.gap)
         if srvce.expiry < now.date():
             srvce.expired = True
         if now.date() > srvce.next_invoice_on:
             days = get_billing_cycle_days_count(srvce.billing_cycle)
             srvce.next_invoice_on = srvce.next_invoice_on + timedelta(
                 days=days)
         srvce.next_invoice_amount = srvce.monthly_cost * get_billing_cycle_months_count(
             srvce.billing_cycle)
         srvce.pending_invoice_count = Invoice.objects.filter(
             subscription=srvce, status=Invoice.PENDING).count()
     try:
         support_code = SupportCode.objects.using(UMBRELLA).filter(
             service=srvce).order_by('-id')[0]
     except IndexError:
         support_code = None
     if support_code and support_code.expiry < now:
         support_code.expired = True
     from echo.models import Balance
     echo_balance, update = Balance.objects.using('wallets').get_or_create(
         service_id=srvce.id)
     context[
         'srvce'] = srvce  # Service named srvce in context to avoid collision with service from template_context_processors
     context['support_code'] = support_code
     context['echo_balance'] = echo_balance
     context['billing_cycles'] = Service.BILLING_CYCLES_CHOICES
     return context
Ejemplo n.º 2
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()
Ejemplo n.º 3
0
def send_invoices():
    """
    This cron task simply sends the Invoice *invoicing_gap* days before Subscription *expiry*
    """
    vendor, config, invoicing_config, connection = _init_base_vars()
    now = timezone.now()
    count, total_amount = 0, 0
    reminder_date_time = now + timedelta(days=invoicing_config.gap)
    subscription_qs = Subscription.objects.filter(status=Subscription.ACTIVE,
                                                  monthly_cost__gt=0, expiry__lt=reminder_date_time.date())
    logger.debug("%d Service candidate for invoice issuance." % subscription_qs.count())
    for subscription in subscription_qs:
        if getattr(settings, 'IS_IKWEN', False):
            if subscription.version == Service.FREE:
                continue
        try:
            pending_invoice = Invoice.objects.get(subscription=subscription, status=Invoice.PENDING)
            logger.debug("%s found for %s. Skipping" % (pending_invoice, subscription))
            continue  # Continue if a Pending invoice for this Subscription is found
        except Invoice.DoesNotExist:
            pass
        member = subscription.member
        number = get_next_invoice_number()
        months_count = None
        if config.__dict__.get('separate_billing_cycle', True):
            months_count = get_billing_cycle_months_count(subscription.billing_cycle)
            amount = subscription.monthly_cost * months_count
        else:
            amount = subscription.product.cost

        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

        entries = []
        if type(subscription) is Service:
            from daraja.models import DARAJA
            partner = subscription.retailer
            if partner and partner.app.slug != DARAJA:
                retail_config = ApplicationRetailConfig.objects.get(partner=partner, app=subscription.app)
                ikwen_price = retail_config.ikwen_monthly_cost
            else:
                ikwen_price = subscription.monthly_cost
            hosting = IkwenInvoiceItem(label=_('Website hosting'), price=ikwen_price, amount=subscription.monthly_cost)
            short_description = _("Project %s" % subscription.domain)
            entry = InvoiceEntry(item=hosting, short_description=short_description, quantity=months_count, total=amount)
            entries = [entry]
            try:
                cr_op_profile = CROperatorProfile.objects.get(service=subscription, is_active=True)
                if cr_op_profile.monthly_cost > 0:
                    plan = cr_op_profile.plan
                    cr_monthly_cost = cr_op_profile.monthly_cost
                    cr_item = IkwenInvoiceItem(label=_('Continuous Rewarding'), price=cr_monthly_cost, amount=cr_monthly_cost)
                    short_description = plan.name
                    cr_amount = months_count * cr_monthly_cost
                    amount += cr_amount
                    entry = InvoiceEntry(item=cr_item, short_description=short_description, quantity=months_count, total=cr_amount)
                    entries.append(entry)
            except CROperatorProfile.DoesNotExist:
                pass
        invoice = Invoice.objects.create(subscription=subscription, member=subscription.member, amount=amount,
                                         number=number, due_date=subscription.expiry, months_count=months_count,
                                         entries=entries, last_reminder=now)
        count += 1
        total_amount += amount
        add_event(vendor, NEW_INVOICE_EVENT, member=member, object_id=invoice.id)

        paid_by_wallet_debit = False
        if getattr(settings, 'IS_IKWEN', False) and subscription.balance >= invoice.amount:
            pay_with_wallet_balance(invoice)
            paid_by_wallet_debit = True
            logger.debug("Invoice for %s paid by wallet debit" % subscription.domain)

        subject, message, sms_text = get_invoice_generated_message(invoice)

        if member.email:
            activate(member.language)
            invoice_url = 'http://ikwen.com' + reverse('billing:invoice_detail', args=(invoice.id,))
            if paid_by_wallet_debit:
                subject = _("Thanks for your payment")
                invoice_url = 'http://ikwen.com' + reverse('billing:invoice_detail', args=(invoice.id,))
                context = {'wallet_debit': True, 'invoice': invoice, 'config': config,
                           'member_name': member.first_name, 'invoice_url': invoice_url, 'cta': _("View invoice")}
                html_content = get_mail_content(subject, '', template_name='billing/mails/wallet_debit_notice.html',
                                                extra_context=context)
            else:
                context = {'invoice_url': invoice_url, 'cta': _("Pay now"), 'currency': config.currency_symbol,
                           'service': vendor, 'config': config, 'logo': config.logo,
                           'project_name': vendor.project_name, 'company_name': config.company_name,
                           'member_name': member.first_name, 'invoice': invoice}
                html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html',
                                                extra_context=context)
            # 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, vendor.domain)
            msg = EmailMessage(subject, html_content, sender, [member.email])
            try:
                invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
                msg.attach_file(invoice_pdf_file)
            except:
                pass
            if paid_by_wallet_debit:
                msg.bcc = ['*****@*****.**']
            msg.content_subtype = "html"
            invoice.last_reminder = timezone.now()
            try:
                if msg.send():
                    logger.debug("1st Invoice reminder for %s sent to %s" % (subscription.domain, member.email))
                    if not paid_by_wallet_debit:
                        invoice.reminders_sent = 1
                        invoice.save()
                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:
            if member.phone:
                if config.sms_sending_method == Config.HTTP_API:
                    send_sms(member.phone, sms_text)
                else:
                    QueuedSMS.objects.create(recipient=member.phone, text=sms_text)

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

    try:
        connection.close()
    finally:
        if count > 0:
            report = SendingReport.objects.create(count=count, total_amount=total_amount)
            sudo_group = Group.objects.get(name=SUDO)
            add_event(vendor, INVOICES_SENT_EVENT, group_id=sudo_group.id, object_id=report.id)
Ejemplo n.º 4
0
def send_invoices():
    """
    This cron task simply sends the Invoice *invoicing_gap* days before Subscription *expiry*
    """
    service = get_service_instance()
    config = service.config
    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)
    count, total_amount = 0, 0
    reminder_date_time = now + timedelta(days=invoicing_config.gap)
    subscription_qs = Subscription.objects.filter(monthly_cost__gt=0, expiry=reminder_date_time.date())
    logger.debug("%d CR Operators candidate for invoice issuance." % subscription_qs.count())
    for subscription in subscription_qs:
        if subscription.plan.raw_monthly_cost == 0:
            continue
        cr_service = subscription.service
        member = cr_service.member
        number = get_next_invoice_number()
        months_count = get_billing_cycle_months_count(subscription.billing_cycle)
        amount = subscription.monthly_cost * months_count

        ikwen_price = subscription.monthly_cost
        hosting = IkwenInvoiceItem(label=_('Website hosting'), price=ikwen_price, amount=subscription.monthly_cost)
        short_description = _("Continuous Rewarding Program for %s" % cr_service.domain)
        entry = InvoiceEntry(item=hosting, short_description=short_description, quantity=months_count, total=amount)
        entries = [entry]
        invoice = Invoice.objects.create(subscription=subscription, amount=amount, number=number,
                                         due_date=subscription.expiry, months_count=months_count, entries=entries)
        count += 1
        total_amount += amount
        add_event(service, NEW_INVOICE_EVENT, member=member, object_id=invoice.id)

        paid_by_wallet_debit = False
        if cr_service.balance >= invoice.amount:
            pay_with_wallet_balance(invoice)
            paid_by_wallet_debit = True
            logger.debug("CR Invoice for %s paid by wallet debit" % cr_service.domain)

        subject, message, sms_text = get_invoice_generated_message(invoice)

        if member.email:
            invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,))
            if paid_by_wallet_debit:
                subject = _("Thanks for your payment")
                invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,))
                context = {'wallet_debit': True, 'invoice': invoice, 'config': config,
                           'invoice_url': invoice_url, 'cta': _("View invoice")}
                html_content = get_mail_content(subject, '', template_name='billing/mails/notice.html',
                                                extra_context=context)
            else:
                html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html',
                                                extra_context={'invoice_url': invoice_url, 'cta': _("Pay now")})
            # 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 = EmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            invoice.last_reminder = timezone.now()
            try:
                if msg.send():
                    logger.debug("1st Invoice reminder for %s sent to %s" % (cr_service.domain, member.email))
                    if not paid_by_wallet_debit:
                        invoice.reminders_sent = 1
                        invoice.save()
                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)

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

    try:
        connection.close()
    finally:
        pass
Ejemplo n.º 5
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