예제 #1
0
def product_set_checkout(request, *args, **kwargs):
    product_id = request.POST['product_id']
    product = Product.objects.get(pk=product_id)
    member = request.user
    now = datetime.now()
    expiry = now + timedelta(days=product.duration)
    subscription = Subscription.objects.create(member=member,
                                               product=product,
                                               since=now,
                                               expiry=expiry)
    number = get_next_invoice_number()
    item = InvoiceItem(label=product.name)
    entry = InvoiceEntry(item=item,
                         short_description=product.short_description,
                         total=product.cost)
    months_count = product.duration / 30
    invoice = Invoice.objects.create(subscription=subscription,
                                     amount=product.cost,
                                     number=number,
                                     due_date=now,
                                     last_reminder=now,
                                     is_one_off=product.is_one_off,
                                     entries=[entry],
                                     months_count=months_count)
    amount = invoice.amount
    notification_url = reverse('billing:product_do_checkout',
                               args=(invoice.id, ))
    cancel_url = request.META['HTTP_REFERER']
    return_url = reverse('billing:invoice_detail', args=(invoice.id, ))
    return invoice, amount, notification_url, return_url, cancel_url
예제 #2
0
 def save_model(self, request, obj, form, change):
     # Send e-mail for manually generated Invoice upon creation
     if change:
         super(InvoiceAdmin, self).save_model(request, obj, form, change)
         return
     obj.number = get_next_invoice_number(auto=False)
     super(InvoiceAdmin, self).save_model(request, obj, form, change)
     member = obj.subscription.member
     service = get_service_instance()
     config = service.config
     subject, message, sms_text = get_invoice_generated_message(obj)
     if member.email:
         add_event(service, NEW_INVOICE_EVENT, member=member, object_id=obj.id)
         invoice_url = service.url + reverse('billing:invoice_detail', args=(obj.id,))
         html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html',
                                         extra_context={'invoice_url': invoice_url})
         # 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>' % (service.project_name, service.domain)
         msg = EmailMessage(subject, html_content, sender, [member.email])
         msg.content_subtype = "html"
         if msg.send(fail_silently=True):
             obj.reminders_sent = 1
             obj.last_reminder = timezone.now()
     if sms_text:
         if member.phone:
             if config.sms_sending_method == Config.HTTP_API:
                 send_sms(member.phone, sms_text)
             else:
                 QueuedSMS.objects.create(recipient=member.phone, text=sms_text)
예제 #3
0
 def place_invoice(self, request, *args, **kwargs):
     school_name = kwargs['school_name']
     weblet = Service.objects.get(project_name_slug=school_name)
     try:
         db = weblet.database
         add_database(db)
         school = SchoolConfig.objects.using(db).get(service=weblet)
         now = datetime.now()
         due_date = now + timedelta(days=7)
         number = get_next_invoice_number()
         from ikwen.billing.utils import Invoice
         app = Application.objects.using(UMBRELLA).get(slug='foulassi')
         cost = 12000
         item = IkwenInvoiceItem(label='School website', price=cost, amount=cost)
         entry = InvoiceEntry(item=item, total=cost)
         invoice_entries = [entry]
         try:
             Invoice.objects.using(UMBRELLA).get(subscription=weblet, months_count=SCHOOL_WEBSITE_MONTH_COUNT)
         except:
             invoice = Invoice(subscription=weblet, member=weblet.member, amount=cost,
                               months_count=SCHOOL_WEBSITE_MONTH_COUNT, number=number,
                               due_date=due_date, last_reminder=now, entries=invoice_entries, is_one_off=True)
             invoice.save()
         school.has_subscribed_website_service = True
         school.save()
         return HttpResponse(json.dumps({'success': True}, 'content-type: text/json'))
     except:
         return HttpResponse(json.dumps({'error': True}, 'content-type: text/json'))
예제 #4
0
파일: views.py 프로젝트: theYogam/Haira
 def get_context_data(self, **kwargs):
     context = super(Receipt, self).get_context_data(**kwargs)
     config = get_service_instance().config
     receipt_id = self.kwargs.get('receipt_id')
     try:
         payment = Payment.objects.select_related(
             'pack', 'member').get(pk=receipt_id)
     except Payment.DoesNotExist:
         raise Http404("Payment not found")
     context['currency_symbol'] = config.currency_symbol
     context['payment'] = payment
     context['amount'] = payment.amount
     context['payment_number'] = get_next_invoice_number()
     return context
예제 #5
0
 def get_context_data(self, **kwargs):
     context = super(Receipt, self).get_context_data(**kwargs)
     config = get_service_instance().config
     receipt_id = self.kwargs.get('receipt_id')
     try:
         reservation = Reservation.objects.select_related('member').get(
             pk=receipt_id)
     except Reservation.DoesNotExist:
         raise Http404("Reservation not found")
     context['currency_symbol'] = config.currency_symbol
     context['payment'] = reservation
     context['member'] = reservation.member
     context['amount'] = int(reservation.post.cost)
     context['payment_number'] = get_next_invoice_number()
     return context
예제 #6
0
def product_set_checkout(request, *args, **kwargs):
    service = get_service_instance()
    product_id = request.POST['product_id']
    product = Product.objects.get(pk=product_id)
    member = request.user
    now = datetime.now()
    expiry = now + timedelta(days=product.duration)
    subscription = Subscription.objects.create(member=member, product=product, since=now, expiry=expiry)
    number = get_next_invoice_number()
    item = InvoiceItem(label=product.name)
    entry = InvoiceEntry(item=item, short_description=product.short_description, total=product.cost)
    months_count = product.duration / 30
    invoice = Invoice.objects.create(subscription=subscription, amount=product.cost, number=number, due_date=now,
                                     last_reminder=now, is_one_off=True, entries=[entry], months_count=months_count)

    request.session['amount'] = product.cost
    request.session['model_name'] = 'billing.Invoice'
    request.session['object_id'] = invoice.id

    mean = request.GET.get('mean', MTN_MOMO)
    request.session['mean'] = mean
    request.session['notif_url'] = service.url # Orange Money only
    request.session['cancel_url'] = service.url + reverse('billing:pricing') # Orange Money only
    request.session['return_url'] = reverse('billing:invoice_detail', args=(invoice.id, ))
예제 #7
0
def deploy(app,
           member,
           business_type,
           project_name,
           billing_plan,
           theme,
           monthly_cost,
           invoice_entries,
           billing_cycle,
           domain=None,
           business_category=None,
           bundle=None,
           partner_retailer=None):
    project_name_slug = slugify(
        project_name)  # Eg: slugify('Cool Shop') = 'cool-shop'
    ikwen_name = project_name_slug.replace('-',
                                           '')  # Eg: cool-shop --> 'coolshop'
    pname = ikwen_name
    i = 0
    while True:
        try:
            Service.objects.using(UMBRELLA).get(project_name_slug=pname)
            i += 1
            pname = "%s%d" % (ikwen_name, i)
        except Service.DoesNotExist:
            ikwen_name = pname
            break
    api_signature = generate_random_key(30, alpha_num=True)
    while True:
        try:
            Service.objects.using(UMBRELLA).get(api_signature=api_signature)
            api_signature = generate_random_key(30, alpha_num=True)
        except Service.DoesNotExist:
            break
    database = ikwen_name
    domain = 'go.' + pname + '.ikwen.com'
    domain_type = Service.SUB
    is_naked_domain = False
    url = 'http://go.ikwen.com/' + pname
    if getattr(settings, 'IS_UMBRELLA', False):
        admin_url = url + '/ikwen' + reverse('ikwen:staff_router')
    else:  # This is a deployment performed by a partner retailer
        admin_url = url + reverse('ikwen:staff_router')
    is_pro_version = billing_plan.is_pro_version
    now = datetime.now()
    expiry = now + timedelta(days=15)

    # Create a copy of template application in the Cloud folder
    app_folder = CLOUD_HOME + '000Tpl/AppSkeleton'
    website_home_folder = CLOUD_FOLDER + ikwen_name
    media_root = CLUSTER_MEDIA_ROOT + ikwen_name + '/'
    media_url = CLUSTER_MEDIA_URL + ikwen_name + '/'
    default_images_folder = CLOUD_FOLDER + '000Tpl/images/000Default'
    theme_images_folder = CLOUD_FOLDER + '000Tpl/images/%s/%s' % (
        theme.template.slug, theme.slug)
    if os.path.exists(theme_images_folder):
        if os.path.exists(media_root):
            shutil.rmtree(media_root)
        shutil.copytree(theme_images_folder, media_root)
        logger.debug("Media folder '%s' successfully created from '%s'" %
                     (media_root, theme_images_folder))
    elif os.path.exists(default_images_folder):
        if os.path.exists(media_root):
            shutil.rmtree(media_root)
        shutil.copytree(default_images_folder, media_root)
        logger.debug("Media folder '%s' successfully created from '%s'" %
                     (media_root, default_images_folder))
    elif not os.path.exists(media_root):
        os.makedirs(media_root)
        logger.debug("Media folder '%s' successfully created empty" %
                     media_root)
    favicons_folder = media_root + 'icons'
    if not os.path.exists(favicons_folder):
        os.makedirs(favicons_folder)
    if os.path.exists(website_home_folder):
        shutil.rmtree(website_home_folder)
    shutil.copytree(app_folder, website_home_folder)
    logger.debug("Service folder '%s' successfully created" %
                 website_home_folder)

    can_manage_delivery_options = False
    if business_type == OperatorProfile.PROVIDER:
        settings_template = 'kakocase/cloud_setup/settings.provider.html'
        can_manage_delivery_options = True
    elif business_type == OperatorProfile.RETAILER:
        settings_template = 'kakocase/cloud_setup/settings.retailer.html'
    elif business_type == OperatorProfile.LOGISTICS:
        settings_template = 'kakocase/cloud_setup/settings.delivery.html'
        auth_code = ikwen_name[:4] + now.strftime('%S')
    elif business_type == OperatorProfile.BANK:
        settings_template = 'kakocase/cloud_setup/settings.bank.html'

    service = Service(member=member,
                      app=app,
                      project_name=project_name,
                      project_name_slug=ikwen_name,
                      domain=domain,
                      database=database,
                      url=url,
                      domain_type=domain_type,
                      expiry=expiry,
                      admin_url=admin_url,
                      billing_plan=billing_plan,
                      billing_cycle=billing_cycle,
                      monthly_cost=monthly_cost,
                      version=Service.TRIAL,
                      retailer=partner_retailer,
                      api_signature=api_signature,
                      home_folder=website_home_folder,
                      settings_template=settings_template)
    service.save(using=UMBRELLA)
    logger.debug("Service %s successfully created" % pname)

    if business_type == OperatorProfile.RETAILER:
        # Copy Categories image to local media folder as the Retailer is allowed to change them
        pass

    # Re-create settings.py file as well as apache.conf file for the newly created project
    secret_key = generate_django_secret_key()
    if is_naked_domain:
        allowed_hosts = '"%s", "www.%s"' % (domain, domain)
    else:
        allowed_hosts = '"go.ikwen.com"'
    settings_tpl = get_template(settings_template)
    settings_context = Context({
        'secret_key': secret_key,
        'ikwen_name': ikwen_name,
        'service': service,
        'static_root': STATIC_ROOT,
        'static_url': STATIC_URL,
        'media_root': media_root,
        'media_url': media_url,
        'allowed_hosts': allowed_hosts,
        'debug': getattr(settings, 'DEBUG', False)
    })
    settings_file = website_home_folder + '/conf/settings.py'
    fh = open(settings_file, 'w')
    fh.write(settings_tpl.render(settings_context))
    fh.close()
    logger.debug("Settings file '%s' successfully created" % settings_file)

    # Import template database and set it up
    if business_type == OperatorProfile.BANK:
        db_folder = CLOUD_FOLDER + '000Tpl/DB/CashFlex'
    else:
        db_folder = CLOUD_FOLDER + '000Tpl/DB/000Default'
        theme_db_folder = CLOUD_FOLDER + '000Tpl/DB/%s/%s' % (
            theme.template.slug, theme.slug)
        if os.path.exists(theme_db_folder):
            db_folder = theme_db_folder

    host = getattr(settings, 'DATABASES')['default'].get('HOST', '127.0.0.1')
    subprocess.call(
        ['mongorestore', '--host', host, '-d', database, db_folder])
    logger.debug("Database %s successfully created on host %s from %s" %
                 (database, host, db_folder))

    add_database_to_settings(database)
    for group in Group.objects.using(database).all():
        try:
            gpl = GroupPermissionList.objects.using(database).get(group=group)
            group.delete()
            group.save(using=database
                       )  # Recreate the group in the service DB with a new id.
            gpl.group = group  # And update GroupPermissionList object with the newly re-created group
            gpl.save(using=database)
        except GroupPermissionList.DoesNotExist:
            group.delete()
            group.save(using=database
                       )  # Re-create the group in the service DB with anyway.
    new_sudo_group = Group.objects.using(database).get(name=SUDO)

    for s in member.get_services():
        db = s.database
        add_database_to_settings(db)
        collaborates_on_fk_list = member.collaborates_on_fk_list + [service.id]
        customer_on_fk_list = member.customer_on_fk_list + [service.id]
        group_fk_list = member.group_fk_list + [new_sudo_group.id]
        Member.objects.using(db).filter(pk=member.id).update(
            collaborates_on_fk_list=collaborates_on_fk_list,
            customer_on_fk_list=customer_on_fk_list,
            group_fk_list=group_fk_list)

    member.collaborates_on_fk_list = collaborates_on_fk_list
    member.customer_on_fk_list = customer_on_fk_list
    member.group_fk_list = group_fk_list

    member.is_iao = True
    member.save(using=UMBRELLA)

    member.is_bao = True
    member.is_staff = True
    member.is_superuser = True

    app.save(using=database)
    member.save(using=database)
    logger.debug("Member %s access rights successfully set for service %s" %
                 (member.username, pname))

    from ikwen.billing.mtnmomo.views import MTN_MOMO
    from ikwen.billing.orangemoney.views import ORANGE_MONEY
    # Copy payment means to local database
    for mean in PaymentMean.objects.using(UMBRELLA).all():
        if mean.slug == 'paypal':
            mean.action_url_name = 'shopping:paypal_set_checkout'
        if mean.slug == MTN_MOMO:
            mean.is_main = True
            mean.is_active = True
        elif mean.slug == ORANGE_MONEY:
            mean.is_main = False
            mean.is_active = True
        else:
            mean.is_main = False
            mean.is_active = False
        mean.save(using=database)
        logger.debug("PaymentMean %s created in database: %s" %
                     (mean.slug, database))

    # Copy themes to local database
    for template in Template.objects.using(UMBRELLA).all():
        template.save(using=database)
    for th in Theme.objects.using(UMBRELLA).all():
        th.save(using=database)
    logger.debug("Template and theme successfully bound for service: %s" %
                 pname)

    FlatPage.objects.using(database).get_or_create(
        url=FlatPage.AGREEMENT,
        title=FlatPage.AGREEMENT.capitalize(),
        content=_('Agreement goes here'))
    FlatPage.objects.using(database).get_or_create(
        url=FlatPage.LEGAL_MENTIONS,
        title=FlatPage.LEGAL_MENTIONS.capitalize(),
        content=_('Legal mentions go here'))

    # Add member to SUDO Group
    obj_list, created = UserPermissionList.objects.using(
        database).get_or_create(user=member)
    obj_list.group_fk_list.append(new_sudo_group.id)
    obj_list.save(using=database)
    logger.debug("Member %s successfully added to sudo group for service: %s" %
                 (member.username, pname))

    # Create wallets
    wallet = OperatorWallet.objects.using('wallets').create(
        nonrel_id=service.id, provider=MTN_MOMO)
    OperatorWallet.objects.using('wallets').create(nonrel_id=service.id,
                                                   provider=ORANGE_MONEY)
    mail_signature = "%s<br>" \
                     "<a href='%s'>%s</a>" % (project_name, 'http://' + domain, domain)
    invitation_message = _(
        "Hey $client<br>"
        "We are inviting you to join our awesome community on ikwen.")
    config = OperatorProfile(
        service=service,
        rel_id=wallet.id,
        media_url=media_url,
        ikwen_share_fixed=billing_plan.tx_share_fixed,
        ikwen_share_rate=billing_plan.tx_share_rate,
        can_manage_delivery_options=can_manage_delivery_options,
        business_type=business_type,
        is_pro_version=is_pro_version,
        theme=theme,
        currency_code='XAF',
        currency_symbol='XAF',
        signature=mail_signature,
        max_products=billing_plan.max_objects,
        decimal_precision=0,
        company_name=project_name,
        contact_email=member.email,
        contact_phone=member.phone,
        business_category=business_category,
        bundle=bundle,
        sms_api_script_url=SMS_API_URL,
        invitation_message=invitation_message)
    config.save(using=UMBRELLA)
    base_config = config.get_base_config()
    base_config.save(using=UMBRELLA)
    from daraja.models import DARAJA
    if partner_retailer:
        partner_retailer.save(using=database)
        try:
            if partner_retailer.app.slug == DARAJA:
                partner_db = partner_retailer.database
                add_database_to_settings(partner_db)
                ikwen_service_partner = Service.objects.using(partner_db).get(
                    project_name_slug='ikwen')
                set_counters(ikwen_service_partner)
                increment_history_field(ikwen_service_partner,
                                        'community_history')
        except:
            logger.error(
                "Could not set Followers count upon Service deployment",
                exc_info=True)

    if bundle:  # Tsunami bundle
        from echo.models import Balance
        token = ''.join(
            [random.SystemRandom().choice(string.digits) for i in range(6)])
        expiry = now + timedelta(days=bundle.support_bundle.duration)
        SupportCode.objects.using(UMBRELLA).create(
            service=service,
            bundle=bundle.support_bundle,
            token=token,
            expiry=expiry)
        Balance.objects.using('wallets').create(service_id=service.id)

    service.save(using=database)
    if business_type == OperatorProfile.LOGISTICS:
        config.auth_code = auth_code

    theme.save(using=database
               )  # Causes theme to be routed to the newly created database
    if business_category:
        business_category.save(using=database)
    config.save(using=database)

    InvoicingConfig.objects.using(database).create()
    logger.debug("Configuration successfully added for service: %s" % pname)

    # Copy samples to local database
    for product in Product.objects.using(database).all():
        product.provider = service
        product.save(using=database)
    logger.debug("Sample products successfully copied to database %s" %
                 database)

    # Create delivery options: Pick-up in store and Free home delivery
    DeliveryOption.objects.using(database).create(
        company=service,
        type=DeliveryOption.PICK_UP_IN_STORE,
        name=_("Pick up in store"),
        slug='pick-up-in-store',
        short_description=_("2H after order"),
        cost=0,
        max_delay=2)
    DeliveryOption.objects.using(database).create(
        company=service,
        type=DeliveryOption.HOME_DELIVERY,
        name=_("Home delivery"),
        slug='home-delivery',
        short_description=_("Max. 72H after order"),
        cost=500,
        max_delay=72)

    # Apache Server cloud_setup
    go_apache_tpl = get_template('core/cloud_setup/apache.conf.local.html')
    apache_context = Context({
        'is_naked_domain': is_naked_domain,
        'domain': domain,
        'home_folder': website_home_folder,
        'ikwen_name': ikwen_name
    })
    if is_naked_domain:
        apache_tpl = get_template('kakocase/cloud_setup/apache.conf.html')
        fh = open(website_home_folder + '/apache.conf', 'w')
        fh.write(apache_tpl.render(apache_context))
        fh.close()
    fh = open(website_home_folder + '/go_apache.conf', 'w')
    fh.write(go_apache_tpl.render(apache_context))
    fh.close()

    vhost = '/etc/apache2/sites-enabled/go_ikwen/' + pname + '.conf'
    subprocess.call(
        ['sudo', 'ln', '-sf', website_home_folder + '/go_apache.conf', vhost])
    if is_naked_domain:
        vhost = '/etc/apache2/sites-enabled/' + domain + '.conf'
        subprocess.call(
            ['sudo', 'ln', '-sf', website_home_folder + '/apache.conf', vhost])
    logger.debug("Apache Virtual Host '%s' successfully created" % vhost)

    # Send notification and Invoice to customer
    number = get_next_invoice_number()
    now = datetime.now()
    invoice_total = 0
    for entry in invoice_entries:
        invoice_total += entry.item.amount * entry.quantity
    invoice = Invoice(subscription=service,
                      member=member,
                      amount=invoice_total,
                      number=number,
                      due_date=expiry,
                      last_reminder=now,
                      reminders_sent=1,
                      is_one_off=True,
                      entries=invoice_entries,
                      months_count=billing_plan.setup_months_count)
    invoice.save(using=UMBRELLA)
    vendor = get_service_instance()

    if member != vendor.member:
        add_event(vendor,
                  SERVICE_DEPLOYED,
                  member=member,
                  object_id=invoice.id)
    if partner_retailer and partner_retailer.app.slug != DARAJA:
        partner_profile = PartnerProfile.objects.using(UMBRELLA).get(
            service=partner_retailer)
        try:
            Member.objects.get(pk=member.id)
        except Member.DoesNotExist:
            member.is_iao = False
            member.is_bao = False
            member.is_staff = False
            member.is_superuser = False
            member.save(using='default')
        service.save(using='default')
        config.save(using='default')
        sender = '%s <no-reply@%s>' % (partner_profile.company_name,
                                       partner_retailer.domain)
        sudo_group = Group.objects.get(name=SUDO)
        ikwen_sudo_gp = Group.objects.using(UMBRELLA).get(name=SUDO)
        add_event(vendor,
                  SERVICE_DEPLOYED,
                  group_id=ikwen_sudo_gp.id,
                  object_id=invoice.id)
    elif partner_retailer and partner_retailer.app.slug == DARAJA:
        try:
            dara_member = partner_retailer.member
            dara = Dara.objects.get(member=dara_member)
            dara_earnings = invoice_total * dara.share_rate / 100
            phone = member.phone
            if len(phone) == 9 and not phone.startswith('237'):
                member.phone = '237' + member.phone

            template_name = 'daraja/mails/remind_referrer.html'
            activate(dara_member.language)
            subject = _("Congratulations ! %s CFA is waiting for you." %
                        intcomma(dara_earnings))
            try:
                extra_context = {
                    'referee': member,
                    'amount': dara_earnings,
                    'invoice_total': intcomma(invoice_total),
                    'deployed_service': service,
                    'dara_name': dara_member.full_name
                }
                html_content = get_mail_content(subject,
                                                template_name=template_name,
                                                extra_context=extra_context)
                sender = 'ikwen Daraja <*****@*****.**>'
                msg = EmailMessage(subject, html_content, sender,
                                   [dara_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 deployed Kakocase website."
                    % dara_member.full_name,
                    exc_info=True)
        except Dara.DoesNotExist:
            logging.error("%s - Customer %s has not been referred" %
                          (service.project_name, member.username))
    else:
        sender = 'ikwen Tsunami <*****@*****.**>'
        sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor,
              SERVICE_DEPLOYED,
              group_id=sudo_group.id,
              object_id=invoice.id)
    invoice_url = 'http://www.ikwen.com' + reverse('billing:invoice_detail',
                                                   args=(invoice.id, ))
    activate(member.language)
    subject = _("Your website %s was created" % project_name)
    html_content = get_mail_content(
        subject,
        template_name='core/mails/service_deployed.html',
        extra_context={
            'service_activated': service,
            'invoice': invoice,
            'member': member,
            'invoice_url': invoice_url
        })
    msg = EmailMessage(subject, html_content, sender, [member.email])
    bcc = ['*****@*****.**', '*****@*****.**']
    if vendor.config.contact_email:
        bcc.append(vendor.config.contact_email)
    msg.bcc = list(set(bcc))
    msg.content_subtype = "html"
    Thread(target=lambda m: m.send(), args=(msg, )).start()
    logger.debug("Notice email submitted to %s" % member.email)
    Thread(target=reload_server).start()
    logger.debug("Apache Scheduled to reload in 5s")
    return service
예제 #8
0
파일: views.py 프로젝트: kiranHR/Project1
 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()
예제 #9
0
def set_my_kids_payment(request, *args, **kwargs):
    school_id = request.POST['school_id']
    student_id = request.POST['student_id']
    cycle = request.POST['my_kids_cycle']
    school = Service.objects.get(pk=school_id)
    student = Student.objects.get(pk=student_id)
    school_config = SchoolConfig.objects.get(service=school)
    Invoice.objects.filter(student=student,
                           is_my_kids=True,
                           status=Invoice.PENDING).delete()
    max_expiry = datetime(day=31, month=8, year=get_school_year() + 1)
    if cycle == Service.YEARLY:
        amount = school_config.my_kids_fees
    elif cycle == Service.QUARTERLY:
        amount = school_config.my_kids_fees_term
    else:
        amount = school_config.my_kids_fees_month
        cycle = Service.MONTHLY
    item = InvoiceItem(label=_("MyKids fees"), amount=amount)
    days = get_billing_cycle_days_count(cycle)
    now = datetime.now()
    expiry = now + timedelta(days=days)
    expiry = min(expiry, max_expiry)
    short_description = now.strftime("%Y/%m/%d") + ' - ' + expiry.strftime(
        "%Y/%m/%d")
    entry = InvoiceEntry(item=item,
                         short_description=short_description,
                         total=amount,
                         quantity_unit='')
    number = get_next_invoice_number()
    member = request.user
    invoice = Invoice.objects.create(number=number,
                                     member=member,
                                     student=student,
                                     school=school,
                                     is_one_off=True,
                                     amount=amount,
                                     my_kids_cycle=cycle,
                                     due_date=now,
                                     entries=[entry],
                                     is_my_kids=True)
    foulassi_weblet = get_service_instance()  # This is Foulassi service itself

    # Transaction is hidden from school if ikwen collects 100%.
    # This is achieved by changing the service_id of transaction
    tx_service_id = school.id if school_config.my_kids_share_rate < 100 else foulassi_weblet.id
    model_name = 'billing.Invoice'
    mean = request.GET.get('mean', MTN_MOMO)
    signature = ''.join([
        random.SystemRandom().choice(string.ascii_letters + string.digits)
        for i in range(16)
    ])
    MoMoTransaction.objects.using(WALLETS_DB_ALIAS).filter(
        object_id=invoice.id).delete()

    tx = MoMoTransaction.objects.using(WALLETS_DB_ALIAS)\
        .create(service_id=tx_service_id, type=MoMoTransaction.CASH_OUT, amount=amount, phone='N/A', model=model_name,
                object_id=invoice.id, task_id=signature, wallet=mean, username=request.user.username, is_running=True)
    notification_url = foulassi_weblet.url + reverse(
        'foulassi:confirm_my_kids_payment', args=(tx.id, signature))
    cancel_url = request.META['HTTP_REFERER']
    return_url = request.META['HTTP_REFERER']
    return invoice, amount, notification_url, return_url, cancel_url
예제 #10
0
def deploy(member,
           project_name,
           billing_plan,
           theme,
           monthly_cost,
           invoice_entries,
           partner_retailer=None):
    app = Application.objects.using(UMBRELLA).get(slug='foulassi')
    project_name_slug = slugify(
        project_name)  # Eg: slugify('Great School') = 'great-school'
    ikwen_name = project_name_slug.replace(
        '-', '')  # Eg: great-school --> 'greatschool'
    pname = ikwen_name
    i = 0
    while True:
        try:
            Service.objects.using(UMBRELLA).get(project_name_slug=pname)
            i += 1
            pname = "%s%d" % (ikwen_name, i)
        except Service.DoesNotExist:
            ikwen_name = pname
            break
    api_signature = generate_random_key(30, alpha_num=True)
    while True:
        try:
            Service.objects.using(UMBRELLA).get(api_signature=api_signature)
            api_signature = generate_random_key(30, alpha_num=True)
        except Service.DoesNotExist:
            break
    database = ikwen_name
    domain = 'go.' + pname + '.ikwen.com'
    domain_type = Service.SUB
    is_naked_domain = False
    url = 'http://go.ikwen.com/' + pname
    admin_url = url + '/ikwen/staffRouter/'
    now = datetime.now()
    expiry = now + timedelta(days=60)

    # Create a copy of template application in the Cloud folder
    app_folder = CLOUD_HOME + '000Tpl/AppSkeleton'
    website_home_folder = CLOUD_FOLDER + ikwen_name
    media_root = CLUSTER_MEDIA_ROOT + ikwen_name + '/'
    media_url = CLUSTER_MEDIA_URL + ikwen_name + '/'
    images_folder = CLOUD_FOLDER + '000Tpl/images/000Default'
    if theme:
        theme_images_folder = CLOUD_FOLDER + '000Tpl/images/%s/%s' % (
            theme.template.slug, theme.slug)
        if os.path.exists(theme_images_folder):
            images_folder = theme_images_folder
    if os.path.exists(images_folder):
        if os.path.exists(media_root):
            shutil.rmtree(media_root)
        shutil.copytree(images_folder, media_root)
        logger.debug("Media folder '%s' successfully created from '%s'" %
                     (media_root, images_folder))
    elif not os.path.exists(media_root):
        os.makedirs(media_root)
        logger.debug("Media folder '%s' successfully created empty" %
                     media_root)
    icons_folder = media_root + 'icons'
    if not os.path.exists(icons_folder):
        os.makedirs(icons_folder)
    if os.path.exists(website_home_folder):
        shutil.rmtree(website_home_folder)
    shutil.copytree(app_folder, website_home_folder)
    logger.debug("Service folder '%s' successfully created" %
                 website_home_folder)

    settings_template = 'foulassi/cloud_setup/settings.html'

    service = Service(member=member,
                      app=app,
                      project_name=project_name,
                      project_name_slug=ikwen_name,
                      domain=domain,
                      database=database,
                      url=url,
                      domain_type=domain_type,
                      expiry=expiry,
                      admin_url=admin_url,
                      billing_plan=billing_plan,
                      billing_cycle=Service.YEARLY,
                      monthly_cost=monthly_cost,
                      version=Service.TRIAL,
                      api_signature=api_signature,
                      home_folder=website_home_folder,
                      settings_template=settings_template,
                      retailer=partner_retailer)
    service.save(using=UMBRELLA)
    logger.debug("Service %s successfully created" % pname)

    # Re-create settings.py file as well as apache.conf file for the newly created project
    secret_key = generate_django_secret_key()
    allowed_hosts = '"go.ikwen.com"'
    settings_tpl = get_template(settings_template)
    settings_context = Context({
        'secret_key': secret_key,
        'ikwen_name': ikwen_name,
        'service': service,
        'static_root': STATIC_ROOT,
        'static_url': STATIC_URL,
        'media_root': media_root,
        'media_url': media_url,
        'allowed_hosts': allowed_hosts,
        'debug': getattr(settings, 'DEBUG', False)
    })
    settings_file = website_home_folder + '/conf/settings.py'
    fh = open(settings_file, 'w')
    fh.write(settings_tpl.render(settings_context))
    fh.close()
    logger.debug("Settings file '%s' successfully created" % settings_file)

    # Import template database and set it up
    db_folder = CLOUD_FOLDER + '000Tpl/DB/000Default'
    if theme:
        theme_db_folder = CLOUD_FOLDER + '000Tpl/DB/%s/%s' % (
            theme.template.slug, theme.slug)
        if os.path.exists(theme_db_folder):
            db_folder = theme_db_folder

    host = getattr(settings, 'DATABASES')['default'].get('HOST', '127.0.0.1')
    from ikwen.core.log import ikwen_error_log_filename
    eh = open(ikwen_error_log_filename, 'a')
    subprocess.call(
        ['mongorestore', '--host', host, '-d', database, db_folder], stderr=eh)
    logger.debug("Database %s successfully created on host %s from %s" %
                 (database, host, db_folder))

    add_database_to_settings(database)
    for group in Group.objects.using(database).all():
        try:
            gpl = GroupPermissionList.objects.using(database).get(group=group)
            group.delete()
            group.save(using=database
                       )  # Recreate the group in the service DB with a new id.
            gpl.group = group  # And update GroupPermissionList object with the newly re-created group
            gpl.save(using=database)
        except GroupPermissionList.DoesNotExist:
            group.delete()
            group.save(using=database
                       )  # Re-create the group in the service DB with anyway.
    new_sudo_group = Group.objects.using(database).get(name=SUDO)

    for s in member.get_services():
        db = s.database
        add_database_to_settings(db)
        collaborates_on_fk_list = member.collaborates_on_fk_list + [service.id]
        customer_on_fk_list = member.customer_on_fk_list + [service.id]
        group_fk_list = member.group_fk_list + [new_sudo_group.id]
        Member.objects.using(db).filter(pk=member.id).update(
            collaborates_on_fk_list=collaborates_on_fk_list,
            customer_on_fk_list=customer_on_fk_list,
            group_fk_list=group_fk_list)

    member.collaborates_on_fk_list = collaborates_on_fk_list
    member.customer_on_fk_list = customer_on_fk_list
    member.group_fk_list = group_fk_list

    member.is_iao = True
    member.save(using=UMBRELLA)

    member.is_bao = True
    member.is_staff = True
    member.is_superuser = True

    app.save(using=database)
    member.save(using=database)
    logger.debug("Member %s access rights successfully set for service %s" %
                 (member.username, pname))

    from ikwen.billing.mtnmomo.views import MTN_MOMO
    # Copy payment means to local database
    for mean in PaymentMean.objects.using(UMBRELLA).all():
        if mean.slug == MTN_MOMO:
            mean.is_main = True
            mean.is_active = True
        else:
            mean.is_main = False
            mean.is_active = True
        mean.save(using=database)
        logger.debug("PaymentMean %s created in database: %s" %
                     (mean.slug, database))

    # Copy themes to local database
    webnode = Application.objects.using(UMBRELLA).get(slug='webnode')
    template_list = list(Template.objects.using(UMBRELLA).filter(app=webnode))
    for template in template_list:
        template.save(using=database)
    for th in Theme.objects.using(UMBRELLA).filter(template__in=template_list):
        th.save(using=database)
    logger.debug("Templates and themes successfully saved for service: %s" %
                 pname)

    FlatPage.objects.using(database).get_or_create(url=FlatPage.AGREEMENT,
                                                   title=FlatPage.AGREEMENT)
    FlatPage.objects.using(database).get_or_create(
        url=FlatPage.LEGAL_MENTIONS, title=FlatPage.LEGAL_MENTIONS)

    # Add member to SUDO Group
    obj_list, created = UserPermissionList.objects.using(
        database).get_or_create(user=member)
    obj_list.group_fk_list.append(new_sudo_group.id)
    obj_list.save(using=database)
    logger.debug("Member %s successfully added to sudo group for service: %s" %
                 (member.username, pname))

    mail_signature = "%s<br>" \
                     "<a href='%s'>%s</a>" % (project_name, 'http://' + domain, domain)
    config = SchoolConfig(service=service,
                          ikwen_share_rate=billing_plan.tx_share_rate,
                          theme=theme,
                          currency_code='XAF',
                          currency_symbol='XAF',
                          decimal_precision=0,
                          signature=mail_signature,
                          company_name=project_name,
                          contact_email=member.email,
                          contact_phone=member.phone,
                          sms_api_script_url=SMS_API_URL,
                          back_to_school_date=back_to_school_date)
    config.save(using=UMBRELLA)
    base_config = config.get_base_config()
    base_config.save(using=UMBRELLA)

    service.save(using=database)
    theme.save(using=database
               )  # Causes theme to be routed to the newly created database
    config.save(using=database)
    logger.debug("Configuration successfully added for service: %s" % pname)

    # Apache Server cloud_setup
    go_apache_tpl = get_template('foulassi/cloud_setup/apache.conf.local.html')
    apache_context = Context({
        'is_naked_domain': is_naked_domain,
        'domain': domain,
        'ikwen_name': ikwen_name
    })
    fh = open(website_home_folder + '/go_apache.conf', 'w')
    fh.write(go_apache_tpl.render(apache_context))
    fh.close()

    vhost = '/etc/apache2/sites-enabled/go_ikwen/' + pname + '.conf'
    subprocess.call(
        ['sudo', 'ln', '-sf', website_home_folder + '/go_apache.conf', vhost])
    logger.debug("Apache Virtual Host '%s' successfully created" % vhost)

    # Send notification and Invoice to customer
    number = get_next_invoice_number()
    now = datetime.now()
    invoice_total = 0
    for entry in invoice_entries:
        invoice_total += entry.total
    invoice = Invoice(subscription=service,
                      member=member,
                      amount=invoice_total,
                      number=number,
                      due_date=expiry,
                      last_reminder=now,
                      reminders_sent=1,
                      is_one_off=True,
                      entries=invoice_entries,
                      months_count=billing_plan.setup_months_count)
    invoice.save(using=UMBRELLA)
    vendor = get_service_instance()

    from daraja.models import DARAJA
    if member != vendor.member:
        add_event(vendor,
                  SERVICE_DEPLOYED,
                  member=member,
                  object_id=invoice.id)
    if partner_retailer and partner_retailer.app.slug != DARAJA:
        partner_profile = PartnerProfile.objects.using(UMBRELLA).get(
            service=partner_retailer)
        try:
            Member.objects.get(pk=member.id)
        except Member.DoesNotExist:
            member.is_iao = False
            member.is_bao = False
            member.is_staff = False
            member.is_superuser = False
            member.save(using='default')
        service.save(using='default')
        config.save(using='default')
        sender = '%s <no-reply@%s>' % (partner_profile.company_name,
                                       partner_retailer.domain)
        sudo_group = Group.objects.get(name=SUDO)
        ikwen_sudo_gp = Group.objects.using(UMBRELLA).get(name=SUDO)
        add_event(vendor,
                  SERVICE_DEPLOYED,
                  group_id=ikwen_sudo_gp.id,
                  object_id=invoice.id)
    else:
        sender = 'ikwen Foulassi <*****@*****.**>'
        sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor,
              SERVICE_DEPLOYED,
              group_id=sudo_group.id,
              object_id=invoice.id)
    invoice_url = 'http://www.ikwen.com' + reverse('billing:invoice_detail',
                                                   args=(invoice.id, ))
    subject = _("Your platform %s was created" % project_name)
    html_content = get_mail_content(
        subject,
        template_name='core/mails/service_deployed.html',
        extra_context={
            'service_activated': service,
            'invoice': invoice,
            'member': member,
            'invoice_url': invoice_url
        })
    msg = EmailMessage(subject, html_content, sender, [member.email])
    bcc = ['*****@*****.**', '*****@*****.**']
    if vendor.config.contact_email:
        bcc.append(vendor.config.contact_email)
    msg.bcc = list(set(bcc))
    msg.content_subtype = "html"
    Thread(target=lambda m: m.send(), args=(msg, )).start()
    logger.debug("Notice email submitted to %s" % member.email)
    Thread(target=reload_server).start()
    logger.debug("Apache Scheduled to reload in 5s")
    return service
예제 #11
0
def deploy(app,
           member,
           project_name,
           billing_plan,
           monthly_cost,
           theme,
           billing_cycle,
           invoice_entries,
           is_pro_version=False):
    project_name_slug = slugify(
        project_name)  # Eg: slugify('Cool Shop') = 'cool-shop'
    ikwen_name = project_name_slug.replace('-',
                                           '')  # Eg: cool-shop --> 'coolshop'
    pname = ikwen_name
    i = 0
    while True:
        try:
            Service.objects.using(UMBRELLA).get(project_name_slug=pname)
            i += 1
            pname = "%s%d" % (ikwen_name, i)
        except Service.DoesNotExist:
            ikwen_name = pname
            break
    api_signature = generate_random_key(30)
    while True:
        try:
            Service.objects.using(UMBRELLA).get(api_signature=api_signature)
            api_signature = generate_random_key(30)
        except Service.DoesNotExist:
            break
    database = ikwen_name
    domain = ikwen_name + '.ikwen.com'
    domain_type = Service.SUB
    is_naked_domain = False
    admin_url = domain + '/ikwen' + reverse('ikwen:staff_router')
    now = datetime.now()
    expiry = now + timedelta(days=15)

    # Create a copy of template application in the Cloud folder
    app_folder = CLOUD_HOME + '000Tpl/AppSkeleton'
    website_home_folder = CLOUD_FOLDER + ikwen_name
    media_root = CLUSTER_MEDIA_ROOT + ikwen_name + '/'
    media_url = CLUSTER_MEDIA_URL + ikwen_name + '/'
    default_images_folder = CLOUD_FOLDER + '000Tpl/images/000Default'
    if os.path.exists(default_images_folder):
        if os.path.exists(media_root):
            shutil.rmtree(media_root)
        shutil.copytree(default_images_folder, media_root)
        logger.debug("Media folder '%s' successfully created from '%s'" %
                     (media_root, default_images_folder))
    elif not os.path.exists(media_root):
        os.makedirs(media_root)
        logger.debug("Media folder '%s' successfully created empty" %
                     media_root)
    favicons_folder = media_root + 'favicons'
    if not os.path.exists(favicons_folder):
        os.makedirs(favicons_folder)
    if os.path.exists(website_home_folder):
        shutil.rmtree(website_home_folder)
    shutil.copytree(app_folder, website_home_folder)
    logger.debug("Service folder '%s' successfully created" %
                 website_home_folder)

    settings_template = 'partnership/cloud_setup/settings.html'

    service = Service(member=member,
                      app=app,
                      project_name=project_name,
                      project_name_slug=ikwen_name,
                      domain=domain,
                      database=database,
                      url='http://' + domain,
                      domain_type=domain_type,
                      expiry=expiry,
                      admin_url='http://' + admin_url,
                      api_signature=api_signature,
                      billing_cycle=billing_cycle,
                      monthly_cost=monthly_cost,
                      version=Service.TRIAL,
                      home_folder=website_home_folder,
                      settings_template=settings_template)
    service.save(using=UMBRELLA)

    # Re-create settings.py file as well as apache.conf file for the newly created project
    secret_key = generate_django_secret_key()
    allowed_hosts = '"%s", "www.%s"' % (domain, domain)
    settings_tpl = get_template(settings_template)
    settings_context = Context({
        'secret_key': secret_key,
        'ikwen_name': ikwen_name,
        'service': service,
        'static_root': STATIC_ROOT,
        'static_url': STATIC_URL,
        'media_root': media_root,
        'media_url': media_url,
        'allowed_hosts': allowed_hosts,
        'debug': getattr(settings, 'DEBUG', False)
    })
    settings_file = website_home_folder + '/conf/settings.py'
    fh = open(settings_file, 'w')
    fh.write(settings_tpl.render(settings_context))
    fh.close()
    logger.debug("Settings file '%s' successfully created" % settings_file)

    # Import template database and set it up
    host = getattr(settings, 'DATABASES')['default'].get('HOST', '127.0.0.1')
    subprocess.call([
        'mongorestore', '--host', host, '-d', database,
        CLOUD_FOLDER + '000Tpl/DB/000Default'
    ])
    add_database_to_settings(database)
    for group in Group.objects.using(database).all():
        try:
            gpl = GroupPermissionList.objects.using(database).get(group=group)
            group.delete()
            group.save(using=database
                       )  # Recreate the group in the service DB with a new id.
            gpl.group = group  # And update GroupPermissionList object with the newly re-created group
            gpl.save(using=database)
        except GroupPermissionList.DoesNotExist:
            group.delete()
            group.save(using=database
                       )  # Re-create the group in the service DB with anyway.
    new_sudo_group = Group.objects.using(database).get(name=SUDO)

    for s in member.get_services():
        db = s.database
        add_database_to_settings(db)
        collaborates_on_fk_list = member.collaborates_on_fk_list + [service.id]
        customer_on_fk_list = member.customer_on_fk_list + [service.id]
        group_fk_list = member.group_fk_list + [new_sudo_group.id]
        Member.objects.using(db).filter(pk=member.id).update(
            collaborates_on_fk_list=collaborates_on_fk_list,
            customer_on_fk_list=customer_on_fk_list,
            group_fk_list=group_fk_list)

    member.collaborates_on_fk_list = collaborates_on_fk_list
    member.customer_on_fk_list = customer_on_fk_list
    member.group_fk_list = group_fk_list

    member.is_iao = True
    member.save(using=UMBRELLA)

    member.is_bao = True
    member.is_staff = True
    member.is_superuser = True

    app.save(using=database)
    member.save(using=database)
    logger.debug("Member %s access rights successfully set for service %s" %
                 (member.username, pname))

    # Copy payment means to local database
    for mean in PaymentMean.objects.using(UMBRELLA).all():
        if mean.slug == MTN_MOMO:
            mean.is_main = True
            mean.is_active = True
        elif mean.slug == ORANGE_MONEY:
            mean.is_main = False
            mean.is_active = True
        else:
            mean.is_main = False
            mean.is_active = False
        mean.save(using=database)
        logger.debug("PaymentMean %s created in database: %s" %
                     (mean.slug, database))

    # Copy themes to local database
    for template in Template.objects.using(UMBRELLA).all():
        template.save(using=database)
    for th in Theme.objects.using(UMBRELLA).all():
        th.save(using=database)
    logger.debug("Template and theme successfully bound for service: %s" %
                 pname)

    # Create Module Blog
    module_blog = Module.objects.using(UMBRELLA).get(slug='module_blog')
    module_blog.is_active = True
    module_blog.save(using=database)
    logger.debug("Module Blog created for service: %s" % pname)

    FlatPage.objects.using(database).create(
        url=FlatPage.AGREEMENT, title=FlatPage.AGREEMENT.capitalize())
    FlatPage.objects.using(database).create(
        url=FlatPage.LEGAL_MENTIONS,
        title=FlatPage.LEGAL_MENTIONS.capitalize().replace('-', ' '))

    # Add member to SUDO Group
    obj_list, created = UserPermissionList.objects.using(
        database).get_or_create(user=member)
    obj_list.group_fk_list.append(new_sudo_group.id)
    obj_list.save(using=database)

    OperatorWallet.objects.using('wallets').create(nonrel_id=service.id,
                                                   provider=MTN_MOMO)
    OperatorWallet.objects.using('wallets').create(nonrel_id=service.id,
                                                   provider=ORANGE_MONEY)
    mail_signature = "%s<br>" \
                     "<a href='%s'>%s</a>" % (project_name, 'http://' + domain, domain)
    config = PartnerProfile(service=service,
                            is_pro_version=is_pro_version,
                            theme=theme,
                            currency_code='XAF',
                            currency_symbol='XAF',
                            signature=mail_signature,
                            company_name=project_name,
                            contact_email=member.email,
                            contact_phone=member.phone)
    config.save(using=UMBRELLA)
    base_config = config.get_base_config()
    base_config.save(using=UMBRELLA)
    service.save(using=database)
    theme.save(using=database
               )  # Causes theme to be routed to the newly created database
    config.save(using=database)

    InvoicingConfig.objects.using(database).create()

    # Apache Server cloud_setup
    if getattr(settings, 'LOCAL_DEV', False):
        apache_tpl = get_template(
            'partnership/cloud_setup/apache.conf.local.html')
    else:
        apache_tpl = get_template('partnership/cloud_setup/apache.conf.html')
    apache_context = Context({
        'is_naked_domain': is_naked_domain,
        'domain': domain,
        'ikwen_name': ikwen_name
    })
    fh = open(website_home_folder + '/apache.conf', 'w')
    fh.write(apache_tpl.render(apache_context))
    fh.close()

    vhost = '/etc/apache2/sites-enabled/' + domain + '.conf'
    subprocess.call(
        ['sudo', 'ln', '-sf', website_home_folder + '/apache.conf', vhost])
    logger.debug("Apache Virtual Host '%s' successfully created" % vhost)

    # Send notification and Invoice to customer
    number = get_next_invoice_number()
    now = datetime.now()
    invoice_total = 0
    for entry in invoice_entries:
        invoice_total += entry.item.amount * entry.quantity
    invoice = Invoice(subscription=service,
                      amount=invoice_total,
                      number=number,
                      due_date=expiry,
                      last_reminder=now,
                      reminders_sent=1,
                      is_one_off=True,
                      entries=invoice_entries,
                      months_count=billing_plan.setup_months_count)
    invoice.save(using=UMBRELLA)
    vendor = get_service_instance()
    sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO)
    add_event(vendor, SERVICE_DEPLOYED, member=member, object_id=invoice.id)
    add_event(vendor,
              SERVICE_DEPLOYED,
              group_id=sudo_group.id,
              object_id=invoice.id)

    invoice_url = 'http://www.ikwen.com' + reverse('billing:invoice_detail',
                                                   args=(invoice.id, ))
    sender = 'ikwen <*****@*****.**>'
    subject = _("Your retailer platform was created")
    html_content = get_mail_content(
        subject,
        '',
        template_name='core/mails/service_deployed.html',
        extra_context={
            'service_activated': service,
            'invoice': invoice,
            'member': member,
            'invoice_url': invoice_url
        })
    msg = EmailMessage(subject, html_content, sender, [member.email])
    msg.bcc = ['*****@*****.**']
    msg.content_subtype = "html"
    Thread(target=lambda m: m.send(), args=(msg, )).start()
    logger.debug("Notice email submitted to %s" % member.email)
    Thread(target=reload_server).start()
    logger.debug("Apache Scheduled to reload in 5s")
    return service
예제 #12
0
파일: crons.py 프로젝트: komsihon/Project1
def send_invoices():
    """
    This cron task simply sends the Invoice *invoicing_gap* days before Subscription *expiry*
    """
    vendor, config, invoicing_config, connection = _init_base_vars()
    now = timezone.now()
    count, total_amount = 0, 0
    reminder_date_time = now + timedelta(days=invoicing_config.gap)
    subscription_qs = Subscription.objects.filter(status=Subscription.ACTIVE,
                                                  monthly_cost__gt=0, expiry__lt=reminder_date_time.date())
    logger.debug("%d Service candidate for invoice issuance." % subscription_qs.count())
    for subscription in subscription_qs:
        if getattr(settings, 'IS_IKWEN', False):
            if subscription.version == Service.FREE:
                continue
        try:
            pending_invoice = Invoice.objects.get(subscription=subscription, status=Invoice.PENDING)
            logger.debug("%s found for %s. Skipping" % (pending_invoice, subscription))
            continue  # Continue if a Pending invoice for this Subscription is found
        except Invoice.DoesNotExist:
            pass
        member = subscription.member
        number = get_next_invoice_number()
        months_count = None
        if config.__dict__.get('separate_billing_cycle', True):
            months_count = get_billing_cycle_months_count(subscription.billing_cycle)
            amount = subscription.monthly_cost * months_count
        else:
            amount = subscription.product.cost

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

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

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

        subject, message, sms_text = get_invoice_generated_message(invoice)

        if member.email:
            activate(member.language)
            invoice_url = 'http://ikwen.com' + reverse('billing:invoice_detail', args=(invoice.id,))
            if paid_by_wallet_debit:
                subject = _("Thanks for your payment")
                invoice_url = 'http://ikwen.com' + reverse('billing:invoice_detail', args=(invoice.id,))
                context = {'wallet_debit': True, 'invoice': invoice, 'config': config,
                           'member_name': member.first_name, 'invoice_url': invoice_url, 'cta': _("View invoice")}
                html_content = get_mail_content(subject, '', template_name='billing/mails/wallet_debit_notice.html',
                                                extra_context=context)
            else:
                context = {'invoice_url': invoice_url, 'cta': _("Pay now"), 'currency': config.currency_symbol,
                           'service': vendor, 'config': config, 'logo': config.logo,
                           'project_name': vendor.project_name, 'company_name': config.company_name,
                           'member_name': member.first_name, 'invoice': invoice}
                html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html',
                                                extra_context=context)
            # Sender is simulated as being no-reply@company_name_slug.com to avoid the mail
            # to be delivered to Spams because of origin check.
            sender = '%s <no-reply@%s>' % (config.company_name, vendor.domain)
            msg = EmailMessage(subject, html_content, sender, [member.email])
            try:
                invoice_pdf_file = generate_pdf_invoice(invoicing_config, invoice)
                msg.attach_file(invoice_pdf_file)
            except:
                pass
            if paid_by_wallet_debit:
                msg.bcc = ['*****@*****.**']
            msg.content_subtype = "html"
            invoice.last_reminder = timezone.now()
            try:
                if msg.send():
                    logger.debug("1st Invoice reminder for %s sent to %s" % (subscription.domain, member.email))
                    if not paid_by_wallet_debit:
                        invoice.reminders_sent = 1
                        invoice.save()
                else:
                    logger.error(u"Invoice #%s generated but mail not sent to %s" % (number, member.email),
                                 exc_info=True)
            except:
                logger.error(u"Connexion error on Invoice #%s to %s" % (number, member.email), exc_info=True)

        if sms_text:
            if member.phone:
                if config.sms_sending_method == Config.HTTP_API:
                    send_sms(member.phone, sms_text)
                else:
                    QueuedSMS.objects.create(recipient=member.phone, text=sms_text)

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

    try:
        connection.close()
    finally:
        if count > 0:
            report = SendingReport.objects.create(count=count, total_amount=total_amount)
            sudo_group = Group.objects.get(name=SUDO)
            add_event(vendor, INVOICES_SENT_EVENT, group_id=sudo_group.id, object_id=report.id)
예제 #13
0
def send_invoices():
    """
    This cron task simply sends the Invoice *invoicing_gap* days before Subscription *expiry*
    """
    service = get_service_instance()
    config = service.config
    now = datetime.now()
    invoicing_config = InvoicingConfig.objects.all()[0]
    connection = mail.get_connection()
    try:
        connection.open()
    except:
        logger.error(u"Connexion error", exc_info=True)
    count, total_amount = 0, 0
    reminder_date_time = now + timedelta(days=invoicing_config.gap)
    subscription_qs = Subscription.objects.filter(monthly_cost__gt=0, expiry=reminder_date_time.date())
    logger.debug("%d CR Operators candidate for invoice issuance." % subscription_qs.count())
    for subscription in subscription_qs:
        if subscription.plan.raw_monthly_cost == 0:
            continue
        cr_service = subscription.service
        member = cr_service.member
        number = get_next_invoice_number()
        months_count = get_billing_cycle_months_count(subscription.billing_cycle)
        amount = subscription.monthly_cost * months_count

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

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

        subject, message, sms_text = get_invoice_generated_message(invoice)

        if member.email:
            invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,))
            if paid_by_wallet_debit:
                subject = _("Thanks for your payment")
                invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,))
                context = {'wallet_debit': True, 'invoice': invoice, 'config': config,
                           'invoice_url': invoice_url, 'cta': _("View invoice")}
                html_content = get_mail_content(subject, '', template_name='billing/mails/notice.html',
                                                extra_context=context)
            else:
                html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html',
                                                extra_context={'invoice_url': invoice_url, 'cta': _("Pay now")})
            # Sender is simulated as being no-reply@company_name_slug.com to avoid the mail
            # to be delivered to Spams because of origin check.
            sender = '%s <no-reply@%s>' % (config.company_name, service.domain)
            msg = EmailMessage(subject, html_content, sender, [member.email])
            msg.content_subtype = "html"
            invoice.last_reminder = timezone.now()
            try:
                if msg.send():
                    logger.debug("1st Invoice reminder for %s sent to %s" % (cr_service.domain, member.email))
                    if not paid_by_wallet_debit:
                        invoice.reminders_sent = 1
                        invoice.save()
                else:
                    logger.error(u"Invoice #%s generated but mail not sent to %s" % (number, member.email),
                                 exc_info=True)
            except:
                logger.error(u"Connexion error on Invoice #%s to %s" % (number, member.email), exc_info=True)

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

    try:
        connection.close()
    finally:
        pass
예제 #14
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
예제 #15
0
def deploy(app,
           member,
           project_name,
           billing_plan,
           setup_cost,
           monthly_cost,
           invoice_entries,
           billing_cycle,
           domain=None,
           provider=None,
           partner_retailer=None):
    project_name_slug = slugify(
        project_name)  # Eg: slugify('Cool Shop') = 'cool-shop'
    ikwen_name = project_name_slug.replace('-',
                                           '')  # Eg: cool-shop --> 'coolshop'
    pname = ikwen_name
    i = 0
    while True:
        try:
            Service.objects.using(UMBRELLA).get(project_name_slug=pname)
            i += 1
            pname = "%s%d" % (ikwen_name, i)
        except Service.DoesNotExist:
            ikwen_name = pname
            break
    database = ikwen_name
    if not domain:
        domain = ikwen_name + '.kakocase.com'
    admin_url = domain + '/ikwen/dashboard'
    domain_type = Service.SUB if '.kakocase.com' in domain else Service.MAIN
    is_pro_version = billing_plan.is_pro_version
    now = datetime.now()
    expiry = now + timedelta(days=15)
    service = Service(member=member,
                      app=app,
                      project_name=project_name,
                      project_name_slug=ikwen_name,
                      domain=domain,
                      database=database,
                      url='http://' + domain,
                      domain_type=domain_type,
                      expiry=expiry,
                      admin_url='http://' + admin_url,
                      billing_plan=billing_plan,
                      billing_cycle=billing_cycle,
                      monthly_cost=monthly_cost,
                      version=Service.TRIAL,
                      retailer=partner_retailer)
    service.save(using=UMBRELLA)

    # Create a copy of template application in the Cloud folder
    app_folder = CLOUD_FOLDER + '000Tpl/AppSkeleton'
    website_home_folder = CLOUD_FOLDER + ikwen_name
    media_root = MEDIA_ROOT + ikwen_name + '/'
    if not os.path.exists(media_root):
        os.makedirs(media_root)
    media_url = MEDIA_URL + ikwen_name + '/'
    if os.path.exists(website_home_folder):
        shutil.rmtree(website_home_folder)
    shutil.copytree(app_folder, website_home_folder)

    # Re-create settings.py file as well as apache.conf file for the newly created project
    secret_key = generate_django_secret_key()
    api_signature = generate_random_key(20)
    allowed_hosts = '%s, www.%s' % (domain, domain)
    settings_tpl = get_template('billing/cloud_setup/settings.html')
    settings_context = Context({
        'secret_key': secret_key,
        'database': database,
        'service': service,
        'static_root': STATIC_ROOT,
        'static_url': STATIC_URL,
        'media_root': media_root,
        'media_url': media_url,
        'app_folder': app_folder,
        'allowed_hosts': allowed_hosts,
        'debug': getattr(settings, 'DEBUG', False)
    })
    fh = open(website_home_folder + '/conf/settings.py', 'w')
    fh.write(settings_tpl.render(settings_context))
    fh.close()

    if service.id not in member.collaborates_on_fk_list:
        member.collaborates_on_fk_list.append(service.id)
    if service not in member.customer_on_fk_list:
        member.customer_on.append(service.id)

    member.is_iao = True
    member.save(using=UMBRELLA)

    # Import template database and set it up
    subprocess.call(
        ['mongorestore', '-d', database, CLOUD_FOLDER + '000Tpl/DB'])
    add_database_to_settings(database)

    member.is_bao = True
    member.is_staff = True
    member.is_superuser = True

    app.save(using=database)
    member.save(using=database)

    # Copy payment means to local database
    for mean in PaymentMean.objects.using(UMBRELLA).all():
        if mean.slug == MTN_MOMO:
            mean.is_main = True
            mean.is_active = True
        else:
            mean.is_main = False
            if is_pro_version:
                mean.is_active = True
            else:
                mean.is_active = False
        mean.save(using=database)

    FlatPage.objects.using(database).create(url=FlatPage.AGREEMENT,
                                            title=FlatPage.AGREEMENT)
    FlatPage.objects.using(database).create(url=FlatPage.LEGAL_MENTIONS,
                                            title=FlatPage.LEGAL_MENTIONS)
    for group in Group.objects.using(database).all():
        try:
            gpl = GroupPermissionList.objects.get(group=group)
            group.id = None
            group.save(using=database
                       )  # Recreate the group in the service DB with a new id.
            gpl.group = group  # And update GroupPermissionList object with the newly re-created group
            gpl.save(using=database)
        except GroupPermissionList.DoesNotExist:
            group.id = None
            group.save(using=database
                       )  # Re-create the group in the service DB with anyway.

    # Add member to SUDO Group
    sudo_group = Group.objects.using(database).get(name=SUDO)
    obj_list, created = UserPermissionList.objects.using(
        database).get_or_create(user=member)
    obj_list.group_fk_list.append(sudo_group.id)
    obj_list.save(using=database)

    mail_signature = "%s<br>" \
                     "<a href='%s'>%s</a>" % (project_name, 'http://' + domain, domain)
    config = OperatorProfile(service=service,
                             api_signature=api_signature,
                             ikwen_share_fixed=billing_plan.tx_share_fixed,
                             ikwen_share_rate=billing_plan.tx_share_rate,
                             is_pro_version=is_pro_version,
                             signature=mail_signature,
                             max_customers=billing_plan.max_objects)
    config.save(using=UMBRELLA)
    base_config = config.get_base_config()
    base_config.save(using=UMBRELLA)
    if partner_retailer:
        partner_retailer.save(using=database)
    service.save(using=database)

    config.save(using=database)
    InvoicingConfig.objects.using(database).create()

    # Apache Server setup
    if getattr(settings, 'LOCAL_DEV'):
        apache_tpl = get_template('core/cloud_setup/apache.conf.local.html')
    else:
        apache_tpl = get_template('core/cloud_setup/apache.conf.html')
    apache_context = Context({'ikwen_name': ikwen_name})
    fh = open(website_home_folder + '/apache.conf', 'w')
    fh.write(apache_tpl.render(apache_context))
    fh.close()

    subprocess.call([
        'sudo', 'ln', '-sf', website_home_folder + '/apache.conf',
        '/etc/apache2/sites-enabled/' + domain + '.conf'
    ])
    subprocess.call(['sudo', 'service', 'apache2', 'reload'])

    # Send notification and Invoice to customer
    number = get_next_invoice_number()
    now = datetime.now()
    invoice_total = 0
    for entry in invoice_entries:
        invoice_total += entry.item.amount * entry.quantity
    invoice = Invoice(subscription=service,
                      amount=invoice_total,
                      number=number,
                      due_date=expiry,
                      last_reminder=now,
                      reminders_sent=1,
                      is_one_off=True,
                      entries=invoice_entries,
                      months_count=billing_plan.setup_months_count)
    invoice.save(using=UMBRELLA)
    vendor = get_service_instance()
    add_event(vendor, NEW_INVOICE_EVENT, member=member, object_id=invoice.id)
    if partner_retailer:
        partner_profile = PartnerProfile.objects.using(UMBRELLA).get(
            service=partner_retailer)
        member.is_bao = False
        member.is_staff = False
        member.is_superuser = False
        member.save(using='default')
        service.save(using='default')
        config.save(using='default')
        sender = '%s <no-reply@%s>' % (partner_profile.company_name,
                                       partner_retailer.domain)
    else:
        sender = 'IKWEN <*****@*****.**>'
    invoice_url = 'http://www.ikwen.com' + reverse('billing:invoice_detail',
                                                   args=(invoice.id, ))
    subject = _("Your Web Billing Platform %s was created" % project_name)
    html_content = get_mail_content(
        subject,
        '',
        template_name='core/mails/service_deployed.html',
        extra_context={
            'service_activated': service,
            'invoice': invoice,
            'member': member,
            'invoice_url': invoice_url
        })
    msg = EmailMessage(subject, html_content, sender, [member.email])
    msg.content_subtype = "html"
    Thread(target=lambda m: m.send(), args=(msg, )).start()
    return service