Пример #1
0
def notify_payment(payment):
    invoice = payment.invoice
    member = invoice.member
    service = get_service_instance()
    config = service.config

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

    if member.email:
        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 = XEmailMessage(subject, html_content, sender, [member.email])
        if invoice_pdf_file:
            msg.attach_file(invoice_pdf_file)
        msg.content_subtype = "html"
        Thread(target=lambda m: m.send(), args=(msg, )).start()
Пример #2
0
def send_dara_notification_email(dara_service, order):
    service = get_service_instance()
    config = service.config
    template_name = 'daraja/mails/new_transaction.html'

    activate(dara_service.member.language)
    subject = _("New transaction on %s" % config.company_name)
    try:
        dashboard_url = 'http://daraja.ikwen.com' + reverse('daraja:dashboard')
        extra_context = {'currency_symbol': config.currency_symbol, 'amount': order.items_cost,
                         'dara_earnings': order.referrer_earnings,
                         'tx_date': order.updated_on.strftime('%Y-%m-%d'),
                         'tx_time': order.updated_on.strftime('%H:%M:%S'),
                         'account_balance': dara_service.balance,
                         'dashboard_url': dashboard_url}
        try:
            dara = Dara.objects.using(UMBRELLA).get(member=dara_service.member)
            extra_context['dara'] = dara
        except:
            pass
        html_content = get_mail_content(subject, template_name=template_name, extra_context=extra_context)
        sender = 'ikwen Daraja <*****@*****.**>'
        msg = XEmailMessage(subject, html_content, sender, [dara_service.member.email])
        msg.content_subtype = "html"
        Thread(target=lambda m: m.send(), args=(msg,)).start()
    except:
        logger.error("Failed to notify %s Dara after follower purchase." % service, exc_info=True)
Пример #3
0
def set_dara_stats(partner_original, service_partner, invoice, dara_earnings):
    set_counters(partner_original)
    increment_history_field(partner_original, 'turnover_history',
                            dara_earnings)
    increment_history_field(partner_original, 'earnings_history',
                            dara_earnings)
    increment_history_field(partner_original, 'transaction_count_history')

    set_counters(service_partner)
    increment_history_field(service_partner, 'earnings_history', dara_earnings)
    increment_history_field(service_partner, 'transaction_count_history')

    ikwen_service = get_service_instance()
    try:
        config = ikwen_service.config
        activate(partner_original.member.language)
        subject = _("New transaction on %s" % config.company_name)
        dashboard_url = 'https://daraja.ikwen.com' + reverse(
            'daraja:dashboard')
        html_content = get_mail_content(
            subject,
            template_name='daraja/mails/new_transaction.html',
            extra_context={
                'currency_symbol': config.currency_symbol,
                'amount': invoice.amount,
                'dara_earnings': dara_earnings,
                'tx_date': invoice.updated_on.strftime('%Y-%m-%d'),
                'tx_time': invoice.updated_on.strftime('%H:%M:%S'),
                'account_balance': partner_original.balance,
                'dashboard_url': dashboard_url
            })
        sender = 'ikwen Daraja <*****@*****.**>'
        msg = XEmailMessage(subject, html_content, sender,
                            [partner_original.member.email])
        msg.content_subtype = "html"
        if getattr(settings, 'UNIT_TESTING', False):
            msg.send()
        else:
            Thread(target=lambda m: m.send(), args=(msg, )).start()
    except:
        logger.error("Failed to notify %s Dara after follower purchase." %
                     partner_original,
                     exc_info=True)
Пример #4
0
def send_order_confirmation_email(request, subject, buyer_name, buyer_email, dara, 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 = 'playground/mails/order_notice.html'
    # invitation_url = 'https://daraja.ikwen.com/daraja/companies/'
    invitation_url = 'https://daraja.ikwen.com/'
    crcy = currencies(request)['CURRENCY']
    sender = 'Daraja Playground <*****@*****.**>'
    extra_context = {'buyer_name': buyer_name, 'order': order, 'message': message,
                     'IS_BANK': getattr(settings, 'IS_BANK', False),
                     'coupon_count': coupon_count, 'crcy': crcy, 'dara': dara}
    if dara:
        extra_context['invitation_url'] = invitation_url
    html_content = get_mail_content(subject, template_name=template_name, extra_context=extra_context)

    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"
    Thread(target=lambda m: m.send(), args=(msg,)).start()
Пример #5
0
def send_order_confirmation_email(request, subject, buyer_name, buyer_email, order, media_order=None, 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):
        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"
            Thread(target=lambda m: m.send(), args=(msg,)).start()
        except:
            logger.error("%s - Failed to send order confirmation email." % service, exc_info=True)
Пример #6
0
def send_welcome_email(member, reward_pack_list=None):
    """
    Sends welcome email upon registration of a Member. The default message can
    be edited from the admin in Config.welcome_message
    Following strings in the message will be replaced as such:

    $member_name  -->  member.first_name

    @param member: Member object to whom message is sent
    @param reward_pack_list: rewards sent to Member if it is a
                             platform with Continuous Rewarding active
    """
    message = None
    if reward_pack_list:
        template_name = 'rewarding/mails/community_welcome_pack.html'
        service = reward_pack_list[0].service
    else:
        service = get_service_instance()
        config = service.config
        if getattr(settings, 'IS_IKWEN', False):
            template_name = 'accesscontrol/mails/welcome_to_ikwen.html'
        else:
            if config.welcome_message.strip():
                message = config.welcome_message.replace(
                    '$member_name', member.first_name)
            template_name = 'accesscontrol/mails/community_welcome.html'
    subject = _("Welcome to %s" % service.project_name)
    html_content = get_mail_content(
        subject,
        message,
        template_name=template_name,
        extra_context={'reward_pack_list': reward_pack_list})
    sender = '%s <no-reply@%s>' % (service.project_name, service.domain)
    msg = XEmailMessage(subject, html_content, sender, [member.email])
    msg.content_subtype = "html"
    Thread(target=lambda m: m.send(), args=(msg, )).start()
Пример #7
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))
Пример #8
0
def confirm_invoice_payment(request, *args, **kwargs):
    tx = kwargs[
        'tx']  # Decoration with @momo_gateway_callback makes 'tx' available in kwargs
    school = Service.objects.get(pk=tx.service_id)
    school_config = SchoolConfig.objects.get(service=school)
    ikwen_charges = tx.amount * school_config.ikwen_share_rate / 100

    tx.fees = ikwen_charges
    tx.save()
    mean = tx.wallet
    db = school.database
    add_database(db)
    invoice = Invoice.objects.using(db).get(pk=tx.object_id)
    payment = Payment.objects.using(db).create(
        invoice=invoice,
        method=Payment.MOBILE_MONEY,
        amount=tx.amount,
        processor_tx_id=tx.processor_tx_id)
    invoice.paid = tx.amount
    invoice.status = Invoice.PAID
    invoice.save()
    student = invoice.student
    if not school_config.is_public or (school_config.is_public
                                       and not invoice.is_tuition):
        amount = tx.amount - ikwen_charges
        school.raise_balance(amount, provider=mean)
    else:
        amount = tx.amount
    student.set_has_new(using=school.database)
    student.save(using='default')

    set_counters(school)
    increment_history_field(school, 'turnover_history', tx.amount)
    increment_history_field(school, 'earnings_history', amount)
    increment_history_field(school, 'transaction_count_history')
    increment_history_field(school, 'transaction_earnings_history', amount)

    member = invoice.member
    if member.email:
        try:
            currency = Currency.active.default().symbol
        except:
            currency = school_config.currency_code
        invoice_url = school.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>' % (school_config.company_name,
                                       school.domain)
        msg = XEmailMessage(subject, html_content, sender, [member.email])
        msg.content_subtype = "html"
        bcc = [
            email.strip()
            for email in school_config.notification_emails.split(',')
            if email.strip()
        ]
        bcc += [school_config.contact_email, school.member.email]
        msg.bcc = list(set(bcc))
        try:
            invoicing_config = get_invoicing_config_instance()
            invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
            msg.attach_file(invoice_pdf_file)
        except:
            pass
    return HttpResponse(
        "Notification for transaction %s received with status %s" %
        (tx.id, tx.status))
Пример #9
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()
Пример #10
0
def confirm_my_kids_payment(request, *args, **kwargs):
    tx = kwargs['tx']
    invoice = Invoice.objects.get(pk=tx.object_id)
    school = invoice.school
    school_config = SchoolConfig.objects.get(service=school)
    ikwen_charges = tx.amount * school_config.my_kids_share_rate / 100
    tx.fees = ikwen_charges
    tx.save(using='wallets')
    mean = tx.wallet

    amount = tx.amount - ikwen_charges
    school.raise_balance(amount, provider=mean)
    share_payment_and_set_stats(invoice, mean, tx)

    invoice.paid = invoice.amount
    invoice.status = Invoice.PAID
    invoice.save()

    member = invoice.member
    student = invoice.student
    max_expiry = datetime(day=31, month=8, year=get_school_year() + 1)
    days = get_billing_cycle_days_count(invoice.my_kids_cycle)
    expiry = datetime.now() + timedelta(days=days)
    expiry = min(expiry, max_expiry)
    student.my_kids_expiry = expiry
    student.my_kids_expired = False
    student.save()

    db = school.database
    add_database(db)
    invoice.save(using=db)
    payment = Payment(invoice=invoice,
                      method=Payment.MOBILE_MONEY,
                      amount=tx.amount,
                      processor_tx_id=tx.processor_tx_id)
    if school_config.my_kids_share_rate < 100:
        # Payment appears in school log panel only if the have something to collect out of that
        payment.save(using=db)

    if member.email:
        try:
            currency = Currency.active.default().symbol
        except:
            currency = school_config.currency_code
        invoice_url = school.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>' % (school_config.company_name,
                                       school.domain)
        msg = XEmailMessage(subject, html_content, sender, [member.email])
        msg.content_subtype = "html"
        try:
            invoicing_config = get_invoicing_config_instance()
            invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
            msg.attach_file(invoice_pdf_file)
        except:
            pass
    return HttpResponse(
        "Notification for transaction %s received with status %s" %
        (tx.id, tx.status))
Пример #11
0
def confirm_correction_payment(request, *args, **kwargs):
    status = request.GET['status']
    message = request.GET['message']
    operator_tx_id = request.GET['operator_tx_id']
    phone = request.GET['phone']
    tx_id = kwargs['tx_id']
    try:
        tx = MoMoTransaction.objects.using(WALLETS_DB_ALIAS).get(pk=tx_id)
        if not getattr(settings, 'DEBUG', False):
            tx_timeout = getattr(settings, 'IKWEN_PAYMENT_GATEWAY_TIMEOUT',
                                 15) * 60
            expiry = tx.created_on + timedelta(seconds=tx_timeout)
            if datetime.now() > expiry:
                return HttpResponse("Transaction %s timed out." % tx_id)
    except:
        raise Http404("Transaction %s not found" % tx_id)

    callback_signature = kwargs.get('signature')
    no_check_signature = request.GET.get('ncs')
    if getattr(settings, 'DEBUG', False):
        if not no_check_signature:
            if callback_signature != tx.task_id:
                return HttpResponse('Invalid transaction signature')
    else:
        if callback_signature != tx.task_id:
            return HttpResponse('Invalid transaction signature')

    if status != MoMoTransaction.SUCCESS:
        return HttpResponse(
            "Notification for transaction %s received with status %s" %
            (tx_id, status))

    school = get_service_instance()
    school_config = SchoolConfig.objects.get(service=school)
    ikwen_charges = tx.amount * school_config.my_kids_share_rate / 100
    teacher_earnings = tx.amount * (100 -
                                    school_config.my_kids_share_rate) / 100

    tx.status = status
    tx.message = message
    tx.processor_tx_id = operator_tx_id
    tx.phone = phone
    tx.is_running = False
    tx.fees = ikwen_charges
    tx.save()
    # mean = tx.wallet
    #
    # amount = tx.amount - ikwen_charges
    # payment = Payment.objects.get(object_id=tx.object_id)

    assignment = Assignment.objects.get(title=tx.message.rstrip(' correction'))
    correction = assignment.assignmentcorrection
    parent = request.user
    subject = assignment.subject
    classroom = assignment.classroom
    teacher = subject.get_teacher(classroom=classroom)
    daraja = Application.objects.get(slug=DARAJA)
    try:
        dara_weblet = Service.objects.using(UMBRELLA).get(
            app=daraja, member=teacher.member)
        dara_db = dara_weblet.database
        dara_weblet_self = Service.objects.using(dara_db).get(
            pk=dara_weblet.id)
        set_counters(dara_weblet_self)
        increment_history_field(dara_weblet_self, 'turnover_history',
                                teacher_earnings)
        increment_history_field(dara_weblet_self, 'earnings_history',
                                teacher_earnings)
        increment_history_field(dara_weblet_self, 'transaction_count_history')
        # share_payment_and_set_stats(invoice, mean)
    except:
        logger.error("The teacher %s doesn't yet have a Dara account" %
                     teacher)
    foulassi_weblet = get_service_instance()
    try:
        currency = Currency.active.default().symbol
    except:
        currency = school_config.currency_code
    body = _(
        "A student just purchase the correction of %(assignment_title)s in %(subject_name)s"
        % {
            'assignment_title': assignment.title,
            'subject_name': subject.name
        })
    member_teacher = teacher.member
    subject = _("New correction of %s paid" % correction)
    cta_url = 'https://daraja.ikwen.com' + reverse('daraja:dashboard')
    html_content = get_mail_content(
        subject,
        template_name='foulassi/mails/correction_paid.html',
        extra_context={
            'teacher': member_teacher.first_name,
            'classroom': classroom,
            'cta_url': cta_url,
            'subject': assignment.subject.name,
            'assignment': assignment,
            'currency': currency
        })
    sender = '%s <no-reply@%s>' % (school_config.company_name, school.domain)
    msg = XEmailMessage(subject, html_content, sender, [member_teacher.email])
    msg.bcc = ['*****@*****.**', '*****@*****.**']
    msg.content_subtype = "html"
    try:
        msg.send()
    except Exception as e:
        logger.debug(e.message)
    send_push(foulassi_weblet, member_teacher, subject, body, cta_url)

    body = _(
        "You just pay the correction of %(assignment_title)s from %(subject_name)s "
        % {
            'assignment_title': assignment.title,
            'subject_name': subject.name
        })
    subject = _("New correction paid")
    if parent.email:
        html_content = get_mail_content(
            subject,
            template_name='foulassi/mails/correction_paid_parent_notif.html',
            extra_context={
                'classroom': classroom,
                'parent_name': parent.first_name,
                'subject': assignment.subject.name,
                'assignment': assignment,
                'currency': currency
            })
        sender = '%s <no-reply@%s>' % (school_config.company_name,
                                       school.domain)
        msg = XEmailMessage(subject, html_content, sender, [parent.email])
        msg.bcc = ['*****@*****.**', '*****@*****.**']
        msg.content_subtype = "html"
        try:
            msg.send()
        except Exception as e:
            logger.debug(e.message)
    send_push(foulassi_weblet, parent, subject, body, cta_url)
    return HttpResponse(
        "Notification for transaction %s received with status %s" %
        (tx_id, status))
Пример #12
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)
Пример #13
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
Пример #14
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))
Пример #15
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
Пример #16
0
def confirm_service_invoice_payment(request, *args, **kwargs):
    """
    This view is run after successful user cashout "MOMO_AFTER_CHECKOUT"
    """
    status = request.GET['status']
    message = request.GET['message']
    operator_tx_id = request.GET['operator_tx_id']
    phone = request.GET['phone']
    tx_id = kwargs['tx_id']
    extra_months = int(kwargs['extra_months'])
    try:
        tx = MoMoTransaction.objects.using(WALLETS_DB_ALIAS).get(pk=tx_id, is_running=True)
        if not getattr(settings, 'DEBUG', False):
            tx_timeout = getattr(settings, 'IKWEN_PAYMENT_GATEWAY_TIMEOUT', 15) * 60
            expiry = tx.created_on + timedelta(seconds=tx_timeout)
            if datetime.now() > expiry:
                return HttpResponse("Transaction %s timed out." % tx_id)

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

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

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

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

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

        set_counters(ikwen_service)
        increment_history_field(ikwen_service, 'cash_out_history',
                                cashout_request.amount)
        increment_history_field(ikwen_service, 'cash_out_count_history')
Пример #18
0
    def post(self, request, *args, **kwargs):
        user = request.user
        post_id = kwargs['post_id']
        _post = Post.objects.get(pk=post_id)
        owner = _post.owner
        subject = _("New request for your ad %s" % _post.ref_ad)
        ref_ad = _post.ref_ad
        service = get_service_instance()
        sender = '%s <*****@*****.**>' % service.project_name

        name = self.request.POST.get('name')
        email = self.request.POST.get('email')
        phone = self.request.POST.get('phone')
        context = self.get_context_data(**kwargs)
        staff_list = [
            member.email for member in Member.objects.filter(is_staff=True)
        ]
        if name and email and phone:
            try:
                html_content = get_mail_content(
                    subject,
                    template_name='enfinchezmoi/mails/send_contacts.html',
                    extra_context={
                        'name': name,
                        'email': email,
                        'phone': phone,
                        'ref_ad': ref_ad
                    })

                recipient_list = [
                    owner.email, owner.member.email, service.member.email,
                    service.config.contact_email
                ]
                recipient_list += staff_list
                context['recipient_list'] = recipient_list
                msg = XEmailMessage(subject, html_content, sender,
                                    recipient_list)
                msg.content_subtype = "html"
                Thread(target=lambda m: m.send(), args=(msg, )).start()

            except Exception as e:
                pass
                context['error'] = e
                return render(request, self.template_name, context)
            context['call_success_message'] = _(
                'Your addresses have been successfully sent to the owner')
            return render(request, self.template_name, context)

        try:
            member = user
            user_message = self.request.POST.get('email_message')
            company_name = service.config.company_name
            html_content = get_mail_content(
                subject,
                template_name='enfinchezmoi/mails/get_information.html',
                extra_context={
                    'member': member,
                    'ref_ad': ref_ad,
                    'company_name': company_name,
                    'user_message': user_message
                })
            recipient_list = [
                owner.email, owner.member.email, service.member.email,
                service.config.contact_email
            ]
            recipient_list += staff_list
            context['recipient_list'] = recipient_list
            msg = XEmailMessage(subject, html_content, sender, recipient_list)
            msg.content_subtype = "html"
            Thread(target=lambda m: m.send(), args=(msg, )).start()

        except Exception as e:
            pass
            # context['error'] = e
            # return render(request, self.template_name, context)
        context['send_email_success_message'] = _(
            'Your message has been successfully sent to the owner')
        return render(request, self.template_name, context)
Пример #19
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))
Пример #20
0
def confirm_service_invoice_payment(request, *args, **kwargs):
    """
    This view is run after successful user cashout "MOMO_AFTER_CHECKOUT"
    """
    tx = kwargs[
        'tx']  # Decoration with @momo_gateway_callback makes 'tx' available in kwargs
    extra_months = int(kwargs['extra_months'])
    payment = Payment.objects.select_related().get(pk=tx.object_id)
    payment.processor_tx_id = tx.processor_tx_id
    payment.save()
    invoice = payment.invoice
    now = datetime.now()
    ikwen_service = get_service_instance()
    invoice.paid += tx.amount
    if invoice.paid >= invoice.amount:
        invoice.status = Invoice.PAID
    invoice.save()
    service = invoice.service
    total_months = invoice.months_count + extra_months
    days = get_days_count(total_months)
    invoicing_config = get_invoicing_config_instance()
    if service.status == Service.SUSPENDED:
        days -= invoicing_config.tolerance  # Catch-up days that were offered before service suspension
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    elif service.expiry:
        expiry = service.expiry + timedelta(days=days)
    else:
        expiry = now + timedelta(days=days)
        expiry = expiry.date()
    service.expiry = expiry
    service.status = Service.ACTIVE
    if invoice.is_one_off:
        service.version = Service.FULL
        try:
            support_bundle = SupportBundle.objects.get(
                type=SupportBundle.TECHNICAL,
                channel=SupportBundle.PHONE,
                cost=0)
            token = ''.join([
                random.SystemRandom().choice(string.digits) for i in range(6)
            ])
            support_expiry = now + timedelta(days=support_bundle.duration)
            SupportCode.objects.create(service=service,
                                       token=token,
                                       bundle=support_bundle,
                                       balance=support_bundle.quantity,
                                       expiry=support_expiry)
            logger.debug("Free Support Code created for %s" % service)
        except SupportBundle.DoesNotExist:
            logger.error("Free Support Code not created for %s" % service,
                         exc_info=True)
    service.save()
    mean = tx.wallet
    is_early_payment = False
    if service.app.slug == 'kakocase' or service.app.slug == 'webnode':
        if invoice.due_date <= now.date():
            is_early_payment = True
        refill_tsunami_messaging_bundle(service, is_early_payment)
    share_payment_and_set_stats(invoice, total_months, mean, tx)
    member = service.member
    vendor = service.retailer
    vendor_is_dara = vendor and vendor.app.slug == DARAJA
    if vendor and not vendor_is_dara:
        add_database_to_settings(vendor.database)
        sudo_group = Group.objects.using(vendor.database).get(name=SUDO)
    else:
        vendor = ikwen_service
        sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor,
              PAYMENT_CONFIRMATION,
              member=member,
              object_id=invoice.id)
    add_event(vendor,
              PAYMENT_CONFIRMATION,
              group_id=sudo_group.id,
              object_id=invoice.id)

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

    if member.email:
        activate(member.language)
        invoice_url = ikwen_service.url + reverse('billing:invoice_detail',
                                                  args=(invoice.id, ))
        subject, message, sms_text = get_payment_confirmation_message(
            payment, member)
        html_content = get_mail_content(
            subject,
            message,
            service=vendor,
            template_name='billing/mails/notice.html',
            extra_context={
                'member_name': member.first_name,
                'invoice': invoice,
                'cta': _("View invoice"),
                'invoice_url': invoice_url,
                'early_payment': is_early_payment
            })
        sender = '%s <no-reply@%s>' % (vendor.config.company_name,
                                       ikwen_service.domain)
        msg = XEmailMessage(subject, html_content, sender, [member.email])
        if vendor != ikwen_service and not vendor_is_dara:
            msg.service = vendor
        if invoice_pdf_file:
            msg.attach_file(invoice_pdf_file)
        msg.content_subtype = "html"
        if getattr(settings, 'UNIT_TESTING', False):
            msg.send()
        else:
            Thread(target=lambda m: m.send(), args=(msg, )).start()
    return HttpResponse("Notification received")
Пример #21
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'])
Пример #22
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))
Пример #23
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))
Пример #24
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