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)
def save_model(self, request, obj, form, change): # Send e-mail for manually generated Invoice upon creation super(SubscriptionAdmin, self).save_model(request, obj, form, change) if change: return # Send e-mail only if e-mail is a valid one. It will be agreed that if a client # does not have an e-mail. we create a fake e-mail that contains his phone number. # So e-mail containing phone number are invalid. member = obj.member service = get_service_instance() config = service.config subject, message, sms_text = get_subscription_registered_message(obj) # This helps differentiates from fake email accounts created as [email protected] if member.email.find(member.phone) < 0: add_event(service, SUBSCRIPTION_EVENT, member=member, object_id=obj.id, model=subscription_model_name) html_content = get_mail_content(subject, message, template_name='billing/mails/notice.html') # 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" Thread(target=lambda m: m.send(), args=(msg,)).start() 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)
def choose_temp_bundle(request, *args, **kwargs): member = request.user if kwargs.get('payment_successful', False): object_id = request.session.get('object_id') if not object_id: object_id = kwargs['object_id'] prepayment = UnitPrepayment.objects.get(pk=object_id) now = datetime.now() expiry = now + timedelta(days=prepayment.duration) prepayment.paid_on = now prepayment.expiry = expiry prepayment.status = Prepayment.CONFIRMED prepayment.save() service = get_service_instance() sudo_group = Group.objects.get(name=SUDO) add_event(service, BUNDLE_PURCHASE, group_id=sudo_group.id, object_id=prepayment.id) add_event(service, BUNDLE_PURCHASE, member=member, object_id=prepayment.id) if type(prepayment) == UnitPrepayment: media = prepayment.get_media() timeout = getattr(settings, 'SECURE_LINK_TIMEOUT', 90) expires = int(time.time()) + timeout * 60 if prepayment.amount == media.download_price: prepayment.download_link = generate_download_link( media.filename, expires) prepayment.save() share_payment_and_set_stats(member.customer, prepayment) messages.success(request, _("Your bundle was successfully activated."))
def check_stock(request, *args, **kwargs): """ Checks stock of product in order and returns the list of product which stock were insufficient stock. Products in that list are grabbed from the provider's database and thus carry the current available stock. """ order = parse_order_info(request) insufficient = [] for entry in order.entries: service = entry.product.provider db = service.database product_original = entry.product.get_from(db) member = service.member if product_original.stock < entry.count: insufficient.append(product_original) try: cet = ConsoleEventType.objects.using('umbrella').get(codename=INSUFFICIENT_STOCK_EVENT) yesterday = datetime.now() - timedelta(days=1) ConsoleEvent.objects.using('umbrella').get(event_type=cet, member=member, object_id=product_original.id, created_on__gte=yesterday) except ConsoleEvent.DoesNotExist: add_event(service, INSUFFICIENT_STOCK_EVENT, member=member, object_id=product_original.id) if len(insufficient) > 0: response = [product.to_dict() for product in insufficient] return HttpResponseRedirect(json.dumps(response), 'content-type: text/json')
def suspend_customers_services(): """ This cron task shuts down service and sends notice of Service suspension for Invoices which tolerance is exceeded. """ vendor, config, invoicing_config, connection = _init_base_vars() now = timezone.now() count, total_amount = 0, 0 deadline = now - timedelta(days=invoicing_config.tolerance) invoice_qs = Invoice.objects.filter(due_date__lte=deadline, status=Invoice.OVERDUE) print ("%d invoice(s) candidate for service suspension." % invoice_qs.count()) for invoice in invoice_qs: subscription = invoice.subscription if not subscription: continue if getattr(settings, 'IS_IKWEN', False): if subscription.version == Service.FREE: continue _set_actual_vendor(subscription, vendor, config) invoice.status = Invoice.EXCEEDED invoice.save() action = getattr(settings, 'SERVICE_SUSPENSION_ACTION', None) if action: count += 1 total_amount += invoice.amount action = import_by_path(action) try: action(subscription) except: logger.error("Error while processing subscription %s" % str(subscription), exc_info=True) continue member = subscription.member add_event(vendor, SERVICE_SUSPENDED_EVENT, member=member, object_id=invoice.id) subject, message, sms_text = get_service_suspension_message(invoice) if member.email: msg = _get_email_msg(member, subject, message, invoice, vendor, config) print ("Sending mail to %s" % member.email) try: if msg.send(): print ("Mail sent to %s" % member.email) else: print ("Sending mail to %s failed" % member.email) 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: 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) 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, SUSPENSION_NOTICES_SENT_EVENT, group_id=sudo_group.id, object_id=report.id)
def submit_order_for_bank_approval(request, order, bank_id, account_number, deal_id=None): merchant = get_service_instance() bank = Service.objects.get(pk=bank_id) payment_mean = PaymentMean.objects.get(slug=bank.project_name_slug) order.payment_mean = payment_mean entry = order.entries[0] product = entry.product product.stock -= entry.count if product.stock == 0: sudo_group = Group.objects.get(name=SUDO) add_event(merchant, SOLD_OUT_EVENT, group_id=sudo_group.id, object_id=product.id) mark_duplicates(product) product.save() bank_db = bank.database add_database(bank_db) try: member = Member.objects.using(bank_db).get(pk=order.member.id) except Member.DoesNotExist: member = order.member member.save(using=bank_db) group = Group.objects.using(bank_db).get(name=COMMUNITY) obj_list, created = UserPermissionList.objects.using(bank_db).get_or_create(user=member) obj_list.group_fk_list.append(group.id) obj_list.save(using=bank_db) account_number_slug = slugify(account_number) try: BankAccount.objects.using(UMBRELLA).get(slug=account_number_slug) except BankAccount.DoesNotExist: m = Member.objects.using(UMBRELLA).get(pk=member.id) b = Service.objects.using(UMBRELLA).get(pk=bank_id) BankAccount.objects.using(UMBRELLA).create(member=m, bank=b, number=account_number, slug=account_number_slug) if deal_id: if len(order.entries) > 1: messages.error(request, _("Terms payment is available only for one single product at a time.")) return HttpResponseRedirect(reverse('shopping:cart')) deal = Deal.objects.using(bank_db).get(pk=deal_id) else: deal = Deal(bank=bank) order.deal = deal order.account_number = account_number order.status = Order.PENDING_FOR_APPROVAL order.save() order.save(using=bank_db) try: del(request.session['object_id']) except: pass subject = _("Order submit for approval") send_order_confirmation_email(request, subject, member.full_name, member.email, order) bank_profile_original = OperatorProfile.objects.using(bank_db).get(service=bank) if bank_profile_original.return_url: nvp_dict = {'member': member.full_name, 'email': member.email, 'phone': member.phone, 'order_rcc': order.rcc.upper(), 'account_number': account_number, 'deal': str(deal), 'merchant': merchant.project_name} Thread(target=lambda url, data: requests.post(url, data=data), args=(bank_profile_original.return_url, nvp_dict)).start() next_url = reverse('shopping:cart', args=(order.id, )) return HttpResponseRedirect(next_url)
def suspend_customers_services(): """ This cron task shuts down service and sends notice of Service suspension for Invoices which tolerance is exceeded. """ service = get_service_instance() config = service.config now = timezone.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 deadline = now - timedelta(days=invoicing_config.tolerance) invoice_qs = Invoice.objects.filter(due_date__lte=deadline, status=Invoice.OVERDUE) logger.debug("%d invoice(s) candidate for service suspension." % invoice_qs.count()) for invoice in invoice_qs: subscription = invoice.subscription if subscription.plan.raw_monthly_cost == 0: continue invoice.status = Invoice.EXCEEDED invoice.save() count += 1 total_amount += invoice.amount try: subscription.is_active = False subscription.save() except: logger.error("Error while processing subscription %s" % str(subscription), exc_info=True) continue member = subscription.service.member add_event(service, SERVICE_SUSPENDED_EVENT, member=member, object_id=invoice.id) logger.debug("Event posted to %s's Console" % member.username) subject, message, sms_text = get_service_suspension_message(invoice) if member.email: invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,)) 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" logger.debug("Sending mail to %s" % member.email) try: if msg.send(): logger.debug("Mail sent to %s" % member.email) else: logger.error(u"Notice of suspension 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) try: connection.close() finally: pass
def send_invoice_overdue_notices(): """ This cron task sends notice of Invoice overdue """ service = get_service_instance() config = service.config now = timezone.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 invoice_qs = Invoice.objects.filter(Q(status=Invoice.PENDING) | Q(status=Invoice.OVERDUE), due_date__lt=now, overdue_notices_sent__lt=3) logger.debug("%d invoice(s) candidate for overdue notice." % invoice_qs.count()) for invoice in invoice_qs: subscription = invoice.subscription if subscription.plan.raw_monthly_cost == 0: continue if invoice.last_overdue_notice: diff = now - invoice.last_overdue_notice else: invoice.status = Invoice.OVERDUE invoice.save() if not invoice.last_overdue_notice or diff.days == invoicing_config.overdue_delay: count += 1 total_amount += invoice.amount member = subscription.service.member add_event(service, OVERDUE_NOTICE_EVENT, member=member, object_id=invoice.id) logger.debug("Event posted to %s's Console" % member.username) subject, message, sms_text = get_invoice_overdue_message(invoice) if member.email: invoice_url = service.url + reverse('billing:invoice_detail', args=(invoice.id,)) 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_overdue_notice = timezone.now() logger.debug("Sending mail to %s" % member.email) try: if msg.send(): logger.debug("Mail sent to %s" % member.email) invoice.overdue_notices_sent += 1 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() try: connection.close() finally: pass
def submit_cashout_request_for_manual_processing(**kwargs): tx = kwargs.get('transaction') if tx: cashout_request = CashOutRequest.objects.using('wallets').get( pk=tx.object_id) weblet = Service.objects.using(UMBRELLA).get(pk=tx.service_id) wallet = OperatorWallet.objects.using('wallets').get( nonrel_id=weblet.id, provider=tx.wallet) config = get_config_model().objects.using(UMBRELLA).get(service=weblet) else: config = kwargs['config'] wallet = kwargs['wallet'] cashout_request = kwargs['cashout_request'] weblet = config.service iao = weblet.member if getattr(settings, 'TESTING', False): IKWEN_SERVICE_ID = getattr(settings, 'IKWEN_ID') ikwen_service = Service.objects.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) retailer = weblet.retailer if retailer: vendor = retailer else: vendor = ikwen_service vendor_config = Config.objects.using(UMBRELLA).get(service=vendor) sender = '%s <no-reply@%s>' % (vendor_config.company_name, vendor.domain) add_event(vendor, CASH_OUT_REQUEST_EVENT, member=iao, object_id=cashout_request.id) subject = _("Cash-out request on %s" % weblet.project_name) html_content = get_mail_content( subject, '', template_name='cashout/mails/request_notice.html', extra_context={ 'cash_out_request': cashout_request, 'weblet': weblet, 'service': vendor, 'config': vendor_config, 'iao': iao, 'wallet': wallet, 'iao_profile': config }) msg = EmailMessage(subject, html_content, sender, [iao.email]) msg.bcc = ['*****@*****.**', '*****@*****.**'] msg.content_subtype = "html" Thread(target=lambda m: m.send(), args=(msg, )).start() return HttpResponse( json.dumps({ 'success': True, 'manual_processing': True }), 'content-type: text/json')
def send_invoice_overdue_notices(): """ This cron task sends notice of Invoice overdue """ vendor, config, invoicing_config, connection = _init_base_vars() now = timezone.now() count, total_amount = 0, 0 invoice_qs = Invoice.objects.filter(Q(status=Invoice.PENDING) | Q(status=Invoice.OVERDUE), due_date__lt=now, overdue_notices_sent__lt=3) print ("%d invoice(s) candidate for overdue notice." % invoice_qs.count()) for invoice in invoice_qs: subscription = invoice.subscription if subscription and getattr(settings, 'IS_IKWEN', False): if subscription.version == Service.FREE: continue _set_actual_vendor(subscription, vendor, config) if invoice.last_overdue_notice: diff = now - invoice.last_overdue_notice else: invoice.status = Invoice.OVERDUE invoice.save() if not invoice.last_overdue_notice or diff.days == invoicing_config.overdue_delay: print ("Processing invoice for Service %s" % str(invoice.subscription)) count += 1 total_amount += invoice.amount member = invoice.subscription.member add_event(vendor, OVERDUE_NOTICE_EVENT, member=member, object_id=invoice.id) subject, message, sms_text = get_invoice_overdue_message(invoice) if member.email: msg = _get_email_msg(member, subject, message, invoice, vendor, config) invoice.last_overdue_notice = timezone.now() print ("Sending mail to %s" % member.email) try: if msg.send(): print ("Mail sent to %s" % member.email) invoice.overdue_notices_sent += 1 else: print ("Sending mail to %s failed" % member.email) logger.error(u"Overdue notice 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) invoice.save() 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) 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, OVERDUE_NOTICES_SENT_EVENT, group_id=sudo_group.id, object_id=report.id)
def put_product_in_trash(request, *args, **kwargs): # TODO: Implement Trash view itself so that people can view and restore the content of the trash config = get_service_instance().config selection = request.GET['selection'].split(',') deleted = [] for product_id in selection: try: product = Product.objects.get(pk=product_id) product.in_trash = True product.visible = False product.save() deleted.append(product_id) if getattr(settings, 'IS_PROVIDER', False): connection = mail.get_connection() try: connection.open() connection_opened = True except: connection_opened = False for retailer_profile in OperatorProfile.objects.filter(business_type=OperatorProfile.RETAILER): member = retailer_profile.service.member service = retailer_profile.service db = service.database add_database_to_settings(db) Product.objects.using(db).get(pk=product_id).delete() ProductCategory.objects.using(db).filter(pk=product.category.id).update(items_count=F('items_count')-1) if product.is_retailed: add_event(service, PROVIDER_REMOVED_PRODUCT_EVENT, member=member, object_id=product_id) if connection_opened: # TODO: Verify what mail looks like after tests once UIs are implemented subject = _("Product taken out by %s" % config.company_name) message = _("Hi %(member_name)s,<br/> The product below was" "removed by <strong>%(company_name)s.</strong> " "It won't appear on your website anymore." % {'member_name': member.first_name, 'company_name': config.company_name}) html_content = get_mail_content(subject, message, template_name='kako/retailer/mails/product_removed.html', extra_context={'product': product, 'service': service, 'provider_id': config.id}) sender = '%s <no-reply@%s.com>' % (service.project_name, service.project_name_slug) msg = EmailMessage(subject, html_content, sender, [member.email]) msg.content_subtype = "html" Thread(target=lambda m: m.send(), args=(msg,)).start() try: connection.close() except: pass except Product.DoesNotExist: message = "Product %s was not found." break else: message = "%d product(s) moved to trash." % len(selection) response = {'message': message, 'deleted': deleted} return HttpResponse(json.dumps(response), 'content-type: text/json')
def save_model(self, request, obj, form, change): if obj.status == CashOutRequest.PAID: if not obj.reference: self.message_user(request, "Reference number missing", messages.ERROR) return obj.teller_username = request.user.username service = Service.objects.get(pk=obj.service_id) wallet = OperatorWallet.objects.using('wallets').get( nonrel_id=service.id, provider=obj.provider) with transaction.atomic(using='wallets'): wallet.balance -= obj.amount_paid wallet.save(using='wallets') iao = service.member if getattr(settings, 'TESTING', False): IKWEN_SERVICE_ID = getattr(settings, 'IKWEN_ID') ikwen_service = Service.objects.get(pk=IKWEN_SERVICE_ID) else: from ikwen.conf.settings import IKWEN_SERVICE_ID ikwen_service = Service.objects.get(pk=IKWEN_SERVICE_ID) retailer = service.retailer if retailer: retailer_config = Config.objects.get(service=retailer) sender = '%s <no-reply@%s>' % ( retailer_config.company_name, retailer.domain) event_originator = retailer else: sender = 'ikwen <*****@*****.**>' event_originator = ikwen_service add_event(event_originator, CASH_OUT_REQUEST_PAID, member=iao, object_id=obj.id) subject = _("Money transfer confirmation") html_content = get_mail_content( subject, '', template_name='cashout/mails/payment_notice.html', extra_context={ 'cash_out_request': obj, 'business': service, 'service': event_originator }) msg = EmailMessage(subject, html_content, sender, [iao.email]) 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', obj.amount) increment_history_field(ikwen_service, 'cash_out_count_history') super(CashOutRequestAdmin, self).save_model(request, obj, form, change)
def set_customer_dara(service, referrer, member): """ Binds referrer to member referred. :param service: Referred Service :param referrer: Member who referred (The Dara) :param member: Referred Member :return: """ try: db = service.database add_database(db) app = Application.objects.using(db).get(slug=DARAJA) dara_service = Service.objects.using(db).get(app=app, member=referrer) customer, change = Customer.objects.using(db).get_or_create(member=member) if customer.referrer: return dara_umbrella = Dara.objects.using(UMBRELLA).get(member=referrer) if dara_umbrella.level == 1 and dara_umbrella.xp == 1: dara_umbrella.xp = 2 dara_umbrella.raise_bonus_cash(100) dara_umbrella.save() customer.referrer = dara_service customer.save() dara_db = dara_service.database add_database(dara_db) member.save(using=dara_db) customer.save(using=dara_db) service_mirror = Service.objects.using(dara_db).get(pk=service.id) set_counters(service_mirror) increment_history_field(service_mirror, 'community_history') add_event(service, REFEREE_JOINED_EVENT, member) diff = datetime.now() - member.date_joined activate(referrer.language) sender = "%s via Playground <*****@*****.**>" % member.full_name if diff.days > 1: subject = _("I'm back on %s !" % service.project_name) else: subject = _("I just joined %s !" % service.project_name) html_content = get_mail_content(subject, template_name='playground/mails/referee_joined.html', extra_context={'referred_service_name': service.project_name, 'referee': member, 'dara': dara_umbrella, 'cta_url': 'https://daraja.ikwen.com/' }) msg = EmailMessage(subject, html_content, sender, [referrer.email]) msg.content_subtype = "html" Thread(target=lambda m: m.send(), args=(msg, )).start() except: logger.error("%s - Error while setting Customer Dara", exc_info=True)
def send_invoice_reminders(): """ This cron task sends Invoice reminder notice to the client if unpaid """ vendor, config, invoicing_config, connection = _init_base_vars() now = timezone.now() count, total_amount = 0, 0 invoice_qs = Invoice.objects.filter(status=Invoice.PENDING, due_date__gte=now.date(), last_reminder__isnull=False) print ("%d invoice(s) candidate for reminder." % invoice_qs.count()) for invoice in invoice_qs: subscription = invoice.subscription if getattr(settings, 'IS_IKWEN', False): if subscription.version == Service.FREE: continue _set_actual_vendor(subscription, vendor, config) diff = now - invoice.last_reminder if diff.days == invoicing_config.reminder_delay: print ("Processing invoice for Service %s" % str(invoice.subscription)) count += 1 total_amount += invoice.amount member = invoice.member add_event(vendor, INVOICE_REMINDER_EVENT, member=member, object_id=invoice.id) subject, message, sms_text = get_invoice_reminder_message(invoice) if member.email: msg = _get_email_msg(member, subject, message, invoice, vendor, config) invoice.last_reminder = timezone.now() print ("Sending mail to %s" % member.email) try: if msg.send(): print ("Mail sent to %s" % member.email) invoice.reminders_sent += 1 else: print ("Sending mail to %s failed" % member.email) logger.error(u"Reminder mail 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) invoice.save() 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) 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, REMINDERS_SENT_EVENT, group_id=sudo_group.id, object_id=report.id)
def save_model(self, request, obj, form, change): if obj.status == CashOutRequest.PAID: if not obj.reference: self.message_user(request, "Reference number missing", messages.ERROR) return obj.teller_username = request.user.username charges = obj.amount * obj.rate / 100 obj.amount_paid = obj.amount * (100 - obj.rate) / 100 service = Service.objects.get(pk=obj.service_id) wallet = OperatorWallet.objects.using('wallets').get(nonrel_id=service.id, provider=obj.provider) method = CashOutMethod.objects.get(slug=obj.provider) address = CashOutAddress.objects.using(UMBRELLA).get(service=service, method=method) with transaction.atomic(using='wallets'): queryset = MoMoTransaction.objects.using('wallets') \ .filter(service_id=service.id, created_on__gt=obj.paid_on, is_running=False, status=MoMoTransaction.SUCCESS, wallet=obj.provider) aggr = queryset.aggregate(Sum('amount')) aggr_fees = queryset.aggregate(Sum('fees')) aggr_dara_fees = queryset.aggregate(Sum('dara_fees')) amount_successful = 0 if aggr['amount__sum']: amount_successful = aggr['amount__sum'] - aggr_fees['fees__sum'] - aggr_dara_fees['dara_fees__sum'] wallet.balance = amount_successful wallet.save(using='wallets') iao = service.member if getattr(settings, 'TESTING', False): IKWEN_SERVICE_ID = getattr(settings, 'IKWEN_ID') ikwen_service = Service.objects.get(pk=IKWEN_SERVICE_ID) else: from ikwen.conf.settings import IKWEN_SERVICE_ID ikwen_service = Service.objects.get(pk=IKWEN_SERVICE_ID) sender = 'ikwen <*****@*****.**>' event_originator = ikwen_service add_event(event_originator, CASH_OUT_REQUEST_PAID, member=iao, object_id=obj.id) subject = _("Money transfer confirmation") html_content = get_mail_content(subject, '', template_name='cashout/mails/payment_notice.html', extra_context={'cash_out_request': obj, 'charges': charges, 'weblet': service, 'address': address, 'service': event_originator}) msg = EmailMessage(subject, html_content, sender, [iao.email]) 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', obj.amount) increment_history_field(ikwen_service, 'cash_out_count_history') super(CashOutRequestAdmin, self).save_model(request, obj, form, change)
def choose_retail_bundle(request, *args, **kwargs): member = request.user # if not member.profile.is_vod_operator: # return HttpResponseForbidden("You are not allowed to order retail bundle.") # bundle_id = request.POST.get('bundle_id') # if bundle_id: # bundle = RetailBundle.objects.get(pk=bundle_id) # status = request.POST.get('status', Prepayment.PENDING) # purchased_quantity = bundle.quantity # prepayment = RetailPrepayment(member=member, amount=bundle.cost, duration=bundle.duration, # adult_authorized=bundle.adult_authorized, status=status) # else: object_id = request.session.get('object_id') if not object_id: object_id = kwargs['object_id'] prepayment = RetailPrepayment.objects.get(pk=object_id) purchased_quantity = prepayment.balance last_retail_prepayment = member.customer.get_last_retail_prepayment() if last_retail_prepayment: if last_retail_prepayment.days_left > 0: balance = last_retail_prepayment.balance + purchased_quantity else: balance = purchased_quantity else: balance = purchased_quantity if kwargs.get('payment_successful', False): prepayment.balance = balance prepayment.status = Prepayment.CONFIRMED prepayment.paid_on = datetime.now() prepayment.save() service = get_service_instance() sudo_group = Group.objects.get(name=SUDO) add_event(service, BUNDLE_PURCHASE, group_id=sudo_group.id, object_id=prepayment.id) add_event(service, BUNDLE_PURCHASE, member=request.user, object_id=prepayment.id) share_payment_and_set_stats(member.customer, prepayment) messages.success(request, _("Your bundle was successfully activated."))
def check_stock_single(request, *args, **kwargs): """ Checks stock of a single product """ product_id = request.GET['product_id'] qty = int(request.GET['qty']) product = Product.objects.get(pk=product_id) service = product.provider member = service.member if product.stock <= qty: try: cet = ConsoleEventType.objects.using('umbrella').get(codename=LOW_STOCK_EVENT) yesterday = datetime.now() - timedelta(days=1) ConsoleEvent.objects.using('umbrella').get(event_type=cet, member=member, object_id=product.id, created_on__gte=yesterday) except ConsoleEvent.DoesNotExist: add_event(service, LOW_STOCK_EVENT, member=member, object_id=product.id) if product.stock < qty: product.stock = product.stock if product.stock >= product.min_order else 0 return HttpResponse(json.dumps({'insufficient': True, 'available': product.stock}), 'content-type: text/json') return HttpResponse(json.dumps({'success': True}), 'content-type: text/json')
def choose_vod_bundle(request, *args, **kwargs): config = get_service_instance().config member = request.user pay_cash = False if config.allow_cash_payment: pay_cash = request.POST.get('pay_cash') == 'yes' if pay_cash: bundle_id = request.POST.get('bundle_id') bundle = VODBundle.objects.get(pk=bundle_id) status = request.POST.get('status', Prepayment.PENDING) prepayment = VODPrepayment(member=member, amount=bundle.cost, duration=bundle.duration, adult_authorized=bundle.adult_authorized, status=status) prepayment.save() elif kwargs.get('payment_successful', False): object_id = request.session.get('object_id') if not object_id: object_id = kwargs['object_id'] prepayment = VODPrepayment.objects.get(pk=object_id) prepayment.status = Prepayment.CONFIRMED prepayment.paid_on = datetime.now() prepayment.save() service = get_service_instance() sudo_group = Group.objects.get(name=SUDO) add_event(service, BUNDLE_PURCHASE, group_id=sudo_group.id, object_id=prepayment.id) add_event(service, BUNDLE_PURCHASE, member=request.user, object_id=prepayment.id) share_payment_and_set_stats(member.customer, prepayment) messages.success(request, _("Your bundle was successfully activated."))
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'])
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")
def create_user(self, username, password=None, **extra_fields): from ikwen.accesscontrol.backends import UMBRELLA from ikwen.conf.settings import IKWEN_SERVICE_ID if not username: raise ValueError('Username must be set') try: phone = str(extra_fields.get('phone', '')) email = extra_fields.get('email', '') if phone and phone.startswith('237') and len( phone ) == 12: # When saving ghost contacts '237' is stripped phone = phone[3:] try: member = Member.objects.get(phone=phone, is_ghost=True) except: try: member = Member.objects.get(email=email, is_ghost=True) except: member = Member.objects.get(username=username, is_ghost=True) member.is_ghost = False member.username = username for key, value in extra_fields.items(): member.__dict__[key] = value except Member.DoesNotExist: member = self.model(username=username, **extra_fields) member.full_name = u'%s %s' % (member.first_name.split(' ')[0], member.last_name.split(' ')[0]) member.tags = slugify(member.first_name + ' ' + member.last_name).replace('-', ' ') service_id = getattr(settings, 'IKWEN_SERVICE_ID') ikwen_community = Group.objects.using(UMBRELLA).get(name=COMMUNITY) member.customer_on_fk_list = [IKWEN_SERVICE_ID] member.group_fk_list = [ikwen_community.id] service = get_service_instance() member.entry_service = service if service_id != IKWEN_SERVICE_ID: service_community = Group.objects.get(name=COMMUNITY) member.customer_on_fk_list.append(service_id) member.group_fk_list.append(service_community.id) member.set_password(password) member.save(using=UMBRELLA) member.save(using='default') perm_list, created = UserPermissionList.objects.using( UMBRELLA).get_or_create(user=member) perm_list.group_fk_list.append(ikwen_community.id) perm_list.save(using=UMBRELLA) from ikwen.accesscontrol.utils import set_member_basic_profile_tags set_member_basic_profile_tags(member) if service_id != IKWEN_SERVICE_ID: # This block is not added above because member must have # already been created before we can add an event for that member # So, DO NOT MOVE THIS ABOVE perm_list, created = UserPermissionList.objects.get_or_create( user=member) perm_list.group_fk_list.append(service_community.id) perm_list.save() sudo_group = Group.objects.get(name=SUDO) add_event(service, MEMBER_JOINED_IN, group_id=sudo_group.id, object_id=member.id) add_event(service, MEMBER_JOINED_IN, member=member, object_id=member.id) return member
def send_free_rewards(): """ This cron task regularly sends free rewards to ikwen member """ ikwen_service = get_service_instance() connection = mail.get_connection() try: connection.open() except: logger.error(u"Connexion error", exc_info=True) t0 = datetime.now() member_list = set() reward_sent = 0 mail_sent = 0 for reward in Reward.objects.select_related('coupon', 'member').filter( status=Reward.PREPARED, count__gt=0): member = reward.member if member in member_list: continue reward_qs = Reward.objects.filter(member=member, status=Reward.PREPARED, count__gt=0) reward_count = reward_qs.count() last_reward = reward_qs.order_by('-id')[0] diff = t0 - last_reward.created_on MIN_FOR_SENDING = getattr(settings, 'CR_MIN_FOR_SENDING', 1) MAX_NRM_DAYS = getattr(settings, 'CR_MAX_NRM_DAYS', 3) # NRM = No Reward Message if reward_count >= MIN_FOR_SENDING or diff.days >= MAX_NRM_DAYS: member_list.add(member) grouped_rewards = group_rewards_by_service(member) reward_sent += 1 total_coupon = 0 total_companies = 0 project_name_list = [] summary = [] for service, reward_list in grouped_rewards.items(): coupons = [ '%s: %d' % (reward.coupon.name, reward.count) for reward in reward_list ] val = service.project_name + ' ' + ','.join(coupons) total_coupon += reward.count total_companies += 1 project_name_list.append(service.project_name) summary.append(val) summary = ' - '.join(summary) if last_reward.type == Reward.JOIN: add_event( ikwen_service, WELCOME_REWARD_OFFERED, member=member, ) else: add_event( ikwen_service, FREE_REWARD_OFFERED, member=member, ) if member.email: if member.language: activate(member.language) else: activate('en') subject = _("%d free coupons are waiting for you" % total_coupon) html_content = get_mail_content( subject, '', template_name='rewarding/mails/free_reward.html', extra_context={ 'member_name': member.first_name, 'grouped_rewards': grouped_rewards, 'total_coupon': total_coupon, 'total_companies': total_companies, 'project_names': ', '.join(project_name_list) }) sender = 'ikwen <*****@*****.**>' msg = EmailMessage(subject, html_content, sender, [member.email]) msg.content_subtype = "html" try: if msg.send(): for service, reward_list in grouped_rewards.items(): db = service.database add_database(db) service_original = Service.objects.using(db).get( pk=service.id) XEmailObject.objects.using(db).create( to=member.email, subject=subject, body=html_content, type=XEmailObject.REWARDING, status="OK") set_counters(service_original) increment_history_field(service_original, 'rewarding_email_history') mail_sent += 1 logger.debug(u"Free reward sent to %s: %s. %s" % (member.username, member.email, summary)) else: logger.error( u"Free reward set but not sent to %s: %s. %s" % (member.username, member.email, summary), exc_info=True) except: logger.error( u"Free reward set but not sent to %s: %s. %s" % (member.username, member.email, summary), 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) for member in member_list: Reward.objects.filter( member=member, status=Reward.PREPARED).update(status=Reward.SENT) try: connection.close() finally: pass duration = datetime.now() - t0 logger.debug("send_free_rewards() run in %d seconds" % duration.seconds)
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
def reward_member(service, member, type, **kwargs): """ Rewards a Member on a Service according the the type of reward. :param service: Service on which the member is interacting :param member: Member actually concerned :param type: Type of reward. Can be Reward.JOIN, Reward.PAYMENT or Reward.MANUAL :param kwargs: kwargs must be provided depending on type. # Reward.PAYMENT, following kwargs are expected: *amount*: amount actually paid by Member *object_id*: ID of the object paid *model_name*: Django style model name. *Eg: trade.Order* # Reward.MANUAL, following kwargs are expected: *coupon*: Coupon being donated to the Member *count*: number of coupon given :return: A tuple (list of JoinRewardPack or PaymentRewardPack, total_coupon_count) """ now = datetime.now() try: # All rewarding actions are run only if # Operator has an active profile. CROperatorProfile.objects.using(UMBRELLA).get(service=service, is_active=True) except CROperatorProfile.DoesNotExist: return None, 0 reward_pack = None reward_pack_list = [] coupon_count = 0 service = Service.objects.using(UMBRELLA).get(pk=service.id) member = Member.objects.using(UMBRELLA).get(pk=member.id) profile, update = CRProfile.objects.get_or_create(member=member) coupon_summary, update = CouponSummary.objects.using( UMBRELLA).get_or_create(service=service, member=member) if type == Reward.JOIN: for coupon in Coupon.objects.using(UMBRELLA).filter(service=service): try: reward_pack = JoinRewardPack.objects.using(UMBRELLA).select_related('service', 'coupon')\ .get(service=service, coupon=coupon) if reward_pack.count > 0: reward_pack_list.append(reward_pack) cumul, update = CumulatedCoupon.objects.using( UMBRELLA).get_or_create(member=member, coupon=coupon) cumul.count += reward_pack.count cumul.save() Reward.objects.using(UMBRELLA).create( service=service, member=member, coupon=coupon, count=reward_pack.count, type=Reward.JOIN, status=Reward.SENT) coupon_summary.count += reward_pack.count coupon_count += reward_pack.count if cumul.count >= coupon.heap_size: CouponWinner.objects.using(UMBRELLA).create( member=member, coupon=coupon) coupon_summary.threshold_reached = True profile.coupon_score += reward_pack.count * coupon.coefficient except JoinRewardPack.DoesNotExist: continue else: profile.reward_score = CRProfile.FREE_REWARD if reward_pack: add_event(service, WELCOME_REWARD_OFFERED, member) elif type == Reward.REFERRAL: for coupon in Coupon.objects.using(UMBRELLA).filter(service=service): try: reward_pack = ReferralRewardPack.objects.using(UMBRELLA).select_related('service', 'coupon')\ .get(service=service, coupon=coupon) if reward_pack.count > 0: reward_pack_list.append(reward_pack) cumul, update = CumulatedCoupon.objects.using( UMBRELLA).get_or_create(member=member, coupon=coupon) cumul.count += reward_pack.count cumul.save() Reward.objects.using(UMBRELLA).create( service=service, member=member, coupon=coupon, count=reward_pack.count, type=Reward.REFERRAL, status=Reward.SENT) coupon_summary.count += reward_pack.count if cumul.count >= coupon.heap_size: CouponWinner.objects.using(UMBRELLA).create( member=member, coupon=coupon) coupon_summary.threshold_reached = True profile.coupon_score += reward_pack.count * coupon.coefficient coupon_count += reward_pack.count except ReferralRewardPack.DoesNotExist: continue else: profile.reward_score = CRProfile.FREE_REWARD if reward_pack: add_event(service, REFERRAL_REWARD_OFFERED, member) elif type == Reward.PAYMENT: amount = kwargs.pop('amount') object_id = kwargs.pop('object_id', None) model_name = kwargs.pop('model_name', None) for coupon in Coupon.objects.using(UMBRELLA).filter(service=service): try: reward_pack = PaymentRewardPack.objects.using(UMBRELLA).select_related('service', 'coupon')\ .get(service=service, coupon=coupon, floor__lt=amount, ceiling__gte=amount) if reward_pack.count > 0: reward_pack_list.append(reward_pack) cumul, update = CumulatedCoupon.objects.using( UMBRELLA).get_or_create(member=member, coupon=coupon) cumul.count += reward_pack.count cumul.save() Reward.objects.using(UMBRELLA).create( service=service, member=member, coupon=coupon, count=reward_pack.count, type=Reward.PAYMENT, status=Reward.SENT, object_id=object_id, amount=amount) coupon_summary.count += reward_pack.count if cumul.count >= coupon.heap_size: CouponWinner.objects.using(UMBRELLA).create( member=member, coupon=coupon) coupon_summary.threshold_reached = True coupon_summary.save() profile.coupon_score += reward_pack.count * coupon.coefficient coupon_count += reward_pack.count except PaymentRewardPack.DoesNotExist: continue else: profile.reward_score = CRProfile.PAYMENT_REWARD if reward_pack: add_event(service, PAYMENT_REWARD_OFFERED, member, object_id=object_id, model=model_name) elif type == Reward.MANUAL: coupon = kwargs.pop('coupon') count = kwargs.pop('count') cumul, update = CumulatedCoupon.objects.using(UMBRELLA).get_or_create( member=member, coupon=coupon) cumul.count += count cumul.save() Reward.objects.using(UMBRELLA).create(service=service, member=member, coupon=coupon, count=count, type=Reward.MANUAL, status=Reward.SENT) coupon_summary.count += count if cumul.count >= coupon.heap_size: CouponWinner.objects.using(UMBRELLA).create(member=member, coupon=coupon) coupon_summary.threshold_reached = True coupon_summary.save() profile.coupon_score += count * coupon.coefficient profile.reward_score = CRProfile.MANUAL_REWARD add_event(service, MANUAL_REWARD_OFFERED, member) profile.save() coupon_summary.save() return reward_pack_list, coupon_count
def deploy(member): app = Application.objects.get(slug=DARAJA) daraja_service = Service.objects.get(project_name_slug=DARAJA) project_name_slug = slugify(member.username) ikwen_name = project_name_slug.replace('-', '') 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) except Service.DoesNotExist: break database = ikwen_name domain = 'go.' + pname + '.ikwen.com' now = datetime.now() expiry = now + timedelta(days=15) service = Service(member=member, app=app, project_name=member.full_name, project_name_slug=ikwen_name, domain=domain, database=database, expiry=expiry, monthly_cost=0, version=Service.FREE, api_signature=api_signature) service.save(using=UMBRELLA) logger.debug("Service %s successfully created" % pname) # Import template database and set it up db_folder = DARAJA_CLOUD_FOLDER + '000Tpl/DB/000Default' 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 s in member.get_services(): db = s.database add_database_to_settings(db) collaborates_on_fk_list = member.collaborates_on_fk_list + [ daraja_service.id ] customer_on_fk_list = member.customer_on_fk_list + [daraja_service.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) member.collaborates_on_fk_list = collaborates_on_fk_list member.customer_on_fk_list = customer_on_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)) # Add member to SUDO Group obj_list, created = UserPermissionList.objects.using( database).get_or_create(user=member) obj_list.save(using=database) logger.debug("Member %s successfully added to sudo group for service: %s" % (member.username, pname)) config = Config(service=service, cash_out_rate=DARAJA_IKWEN_SHARE_RATE, currency_code='XAF', currency_symbol='XAF', decimal_precision=0, company_name=ikwen_name, contact_email=member.email, contact_phone=member.phone, sms_api_script_url=SMS_API_URL) config.save(using=UMBRELLA) service.save(using=database) # Send notification and Invoice to customer vendor = get_service_instance() add_event(vendor, SERVICE_DEPLOYED, member=member) sender = 'ikwen Daraja <*****@*****.**>' sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO) add_event(vendor, SERVICE_DEPLOYED, group_id=sudo_group.id) subject = _("Welcome to the business network.") registered_company_list_url = vendor.url + reverse( 'daraja:registered_company_list') html_content = get_mail_content( subject, template_name='daraja/mails/service_deployed.html', extra_context={ 'registered_company_list_url': registered_company_list_url, 'member': member }) msg = EmailMessage(subject, html_content, sender, [member.email]) bcc = ['*****@*****.**'] 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) return service
def after_order_confirmation(order, update_stock=True): member = order.member service = get_service_instance() config = service.config delcom = order.delivery_option.company delcom_db = delcom.database add_database(delcom_db) delcom_profile_original = OperatorProfile.objects.using(delcom_db).get(pk=delcom.config.id) dara, dara_service_original, provider_mirror = None, None, None sudo_group = Group.objects.get(name=SUDO) customer = member.customer referrer = customer.referrer referrer_share_rate = 0 # Test if the customer has been referred if referrer: referrer_db = referrer.database add_database(referrer_db) try: dara = Dara.objects.get(member=referrer.member) except Dara.DoesNotExist: logging.error("%s - Dara %s not found" % (service.project_name, member.username)) try: dara_service_original = Service.objects.using(referrer_db).get(pk=referrer.id) except Dara.DoesNotExist: logging.error("%s - Dara service not found in %s database for %s" % (service.project_name, referrer_db, referrer.project_name)) try: provider_mirror = Service.objects.using(referrer_db).get(pk=service.id) except Service.DoesNotExist: logging.error("%s - Provider Service not found in %s database for %s" % (service.project_name, referrer_db, referrer.project_name)) packages_info = order.split_into_packages(dara) if delcom != service and delcom_profile_original.payment_delay == OperatorProfile.STRAIGHT: set_logicom_earnings_and_stats(order) for provider_db in packages_info.keys(): package = packages_info[provider_db]['package'] provider_earnings = package.provider_earnings raw_provider_revenue = package.provider_revenue provider_revenue = raw_provider_revenue if package.provider == delcom: provider_revenue += order.delivery_option.cost + order.delivery_option.packing_cost provider_earnings += order.delivery_earnings else: provider_revenue += order.delivery_option.packing_cost provider_earnings += order.delivery_option.packing_cost * (100 - config.ikwen_share_rate) / 100 provider_profile_umbrella = packages_info[provider_db]['provider_profile'] provider_profile_original = provider_profile_umbrella.get_from(provider_db) provider_original = provider_profile_original.service if delcom == service: provider_original.raise_balance(provider_earnings, provider=order.payment_mean.slug) else: if delcom_profile_original.return_url: nvp_dict = package.get_nvp_api_dict() Thread(target=lambda url, data: requests.post(url, data=data), args=(delcom_profile_original.return_url, nvp_dict)).start() if provider_profile_original.payment_delay == OperatorProfile.STRAIGHT: if package.provider_earnings > 0: provider_original.raise_balance(provider_earnings, provider=order.payment_mean.slug) if provider_profile_original.return_url: nvp_dict = package.get_nvp_api_dict() Thread(target=lambda url, data: requests.post(url, data=data), args=(provider_profile_original.return_url, nvp_dict)).start() set_counters(config) increment_history_field(config, 'orders_count_history') increment_history_field(config, 'items_traded_history', order.items_count) increment_history_field(config, 'turnover_history', provider_revenue) increment_history_field(config, 'earnings_history', provider_earnings) set_counters(customer) customer.last_payment_on = datetime.now() increment_history_field(customer, 'orders_count_history') increment_history_field(customer, 'items_purchased_history', order.items_count) increment_history_field(customer, 'turnover_history', provider_revenue) increment_history_field(customer, 'earnings_history', provider_earnings) # Test whether the referrer (of the current customer) is a Dara if dara: referrer_share_rate = dara.share_rate send_dara_notification_email(dara_service_original, order) set_counters(dara) dara.last_transaction_on = datetime.now() increment_history_field(dara, 'orders_count_history') increment_history_field(dara, 'items_traded_history', order.items_count) increment_history_field(dara, 'turnover_history', provider_revenue) increment_history_field(dara, 'earnings_history', provider_earnings) if dara_service_original: set_counters(dara_service_original) increment_history_field(dara_service_original, 'transaction_count_history') increment_history_field(dara_service_original, 'turnover_history', raw_provider_revenue) increment_history_field(dara_service_original, 'earnings_history', order.referrer_earnings) if dara_service_original: set_counters(provider_mirror) increment_history_field(provider_mirror, 'transaction_count_history') increment_history_field(provider_mirror, 'turnover_history', raw_provider_revenue) increment_history_field(provider_mirror, 'earnings_history', order.referrer_earnings) try: member_ref = Member.objects.using(referrer_db).get(pk=member.id) except Member.DoesNotExist: member.save(using=referrer_db) member_ref = Member.objects.using(referrer_db).get(pk=member.id) member.customer.save(using=referrer_db) customer_ref = member_ref.customer set_counters(customer_ref) customer_ref.last_payment_on = datetime.now() increment_history_field(customer_ref, 'orders_count_history') increment_history_field(customer_ref, 'items_purchased_history', order.items_count) increment_history_field(customer_ref, 'turnover_history', raw_provider_revenue) increment_history_field(customer_ref, 'earnings_history', order.retailer_earnings) dara_umbrella = Dara.objects.using(UMBRELLA).get(member=dara.member) if dara_umbrella.level == 1 and dara_umbrella.xp == 2: dara_umbrella.xp = 3 dara_umbrella.raise_bonus_cash(200) dara_umbrella.save() category_list = [] # Adding a 100 bonus in dara account to have buy online try: dara_as_buyer = Dara.objects.using(UMBRELLA).get(member=member) if dara_as_buyer.level == 1 and dara_as_buyer.xp == 0: dara_as_buyer.xp = 1 dara_as_buyer.raise_bonus_cash(100) dara_as_buyer.save() except Dara.DoesNotExist: logging.error("The customer is not yet a Dara") for entry in order.entries: product = Product.objects.get(pk=entry.product.id) provider_service = product.provider provider_profile_umbrella = OperatorProfile.objects.using(UMBRELLA).get(service=provider_service) category = product.category turnover = entry.count * product.retail_price set_counters(category) provider_earnings = turnover * (100 - referrer_share_rate - provider_profile_umbrella.ikwen_share_rate) / 100 increment_history_field(category, 'earnings_history', provider_earnings) increment_history_field(category, 'turnover_history', turnover) increment_history_field(category, 'items_traded_history', entry.count) if category not in category_list: increment_history_field(category, 'orders_count_history') category_list.append(category) if update_stock: product.stock -= entry.count if product.stock == 0: add_event(service, SOLD_OUT_EVENT, group_id=sudo_group.id, object_id=product.id) mark_duplicates(product) product.save() set_counters(product) increment_history_field(product, 'units_sold_history', entry.count) add_event(service, NEW_ORDER_EVENT, group_id=sudo_group.id, object_id=order.id)
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
def confirm_shipping(request, *args, **kwargs): order_id = request.GET.get('order_id') package_id = request.GET.get('package_id') try: if package_id: package = Package.objects.get(pk=package_id) package.status = Order.SHIPPED package.confirmed_on = datetime.now() package.confirmed_by = request.user package.save() order = package.order else: order = Order.objects.get(pk=order_id) order.status = Order.SHIPPED order.confirmed_on = datetime.now() order.confirmed_by = request.user order.save() except Order.DoesNotExist: response = {'error': _("No Order found with this ID: %s" % order_id)} return HttpResponse(json.dumps(response), 'content-type: text/json') except Package.DoesNotExist: response = { 'error': _("No Package found with this ID: %s" % package_id) } return HttpResponse(json.dumps(response), 'content-type: text/json') except: response = {'error': _("Unknow error occured")} return HttpResponse(json.dumps(response), 'content-type: text/json') else: response = {'success': True} delivery_company = order.delivery_option.company # Set provider balance for those with payment_delay=UPON_CONFIRMATION. # Those with payment_delay=STRAIGHT had their balance set in confirm_checkout() for package in order.package_set.all(): provider_service_umbrella = Service.objects.using(UMBRELLA).get( pk=package.provider.id) if delivery_company.id != provider_service_umbrella.id: provider_profile_umbrella = provider_service_umbrella.config if provider_profile_umbrella.payment_delay == OperatorProfile.UPON_CONFIRMATION: provider_db = provider_service_umbrella.database add_database_to_settings(provider_db) provider_original = Service.objects.using(provider_db).get( pk=package.provider.id) provider_original.raise_balance(package.provider_earnings, order.payment_mean.slug) if getattr(settings, 'IS_PROVIDER', False): service = get_service_instance() retailer_service = order.retailer if retailer_service != service: retailer_earnings = order.retailer_earnings if delivery_company == retailer_service: retailer_earnings += order.delivery_earnings retailer_profile = retailer_service.config retailer_db = retailer_service.database add_database_to_settings(retailer_db) retailer_profile_original = OperatorProfile.objects.using( retailer_db).get(pk=retailer_profile.id) set_counters(retailer_profile_original) increment_history_field(retailer_profile_original, 'earnings_history', retailer_earnings) retailer_profile.report_counters_to_umbrella() retailer_profile_original.raise_balance(retailer_earnings, order.payment_mean.slug) if order.delivery_option.type == DeliveryOption.HOME_DELIVERY: if order.member: add_event(service, ORDER_SHIPPED_EVENT, member=order.member, object_id=order.id) subject = _("Your order was shipped") else: if order.member: add_event(service, ORDER_PACKAGED_EVENT, member=order.member, object_id=order.id) subject = _("Your order is packaged and ready") if order.aotc: buyer_name = order.anonymous_buyer.name email = order.anonymous_buyer.email else: member = order.member buyer_name = member.full_name email = member.email html_content = get_mail_content( subject, '', template_name='shopping/mails/order_notice.html', extra_context={ 'rcc': order.rcc.upper(), 'buyer_name': buyer_name, 'order': order }) sender = '%s <no-reply@%s>' % (service.project_name, service.domain) msg = EmailMessage(subject, html_content, sender, [email]) msg.content_subtype = "html" Thread(target=lambda m: m.send(), args=(msg, )).start() return HttpResponse(json.dumps(response), 'content-type: text/json')
def save_formset(self, request, form, formset, change): instances = formset.save(commit=False) total_amount = 0 instance = None for instance in instances: if isinstance(instance, Payment): total_amount += instance.amount if instance.cashier: # Instances with non null cashier are those that previously existed. # setting them to None allows to ignore them at the end of the loop # since we want to undertake action only for newly added Payment instance = None continue instance.cashier = request.user instance.save() if instance: # TODO: Check if the last payment is newly added # Notice email is sent only for the last saved Payment, # this is why this code is not run within the "for" loop above member = instance.invoice.subscription.member service = get_service_instance() config = service.config invoice = instance.invoice s = invoice.service days = get_days_count(invoice.months_count) if s.status == Service.SUSPENDED: invoicing_config = get_invoicing_config_instance() days -= invoicing_config.tolerance # Catch-up days that were offered before service suspension expiry = datetime.now() + timedelta(days=days) expiry = expiry.date() elif s.expiry: expiry = s.expiry + timedelta(days=days) else: expiry = datetime.now() + timedelta(days=days) expiry = expiry.date() s.expiry = expiry s.status = Service.ACTIVE if invoice.is_one_off: s.version = Service.FULL s.save() share_payment_and_set_stats(invoice, invoice.months_count) if s.retailer: db = s.retailer.database Service.objects.using(db).filter(pk=s.id).update( expiry=s.expiry, status=s.status, version=s.version) sudo_group = Group.objects.using(UMBRELLA).get(name=SUDO) add_event(service, PAYMENT_CONFIRMATION, group_id=sudo_group.id, object_id=invoice.id) add_event(service, PAYMENT_CONFIRMATION, member=member, object_id=invoice.id) subject, message, sms_text = get_payment_confirmation_message( instance, member) if member.email: 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( instance, 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 = EmailMessage(subject, html_content, sender, [member.email]) msg.content_subtype = "html" Thread(target=lambda m: m.send(), args=(msg, )).start() 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) if total_amount >= invoice.amount: invoice.status = AbstractInvoice.PAID invoice.save()
def after_order_confirmation(order, media_order=None, update_stock=True): member = order.member service = get_service_instance() config = service.config delcom = order.delivery_option.company delcom_db = delcom.database add_database(delcom_db) sudo_group = Group.objects.get(name=SUDO) customer = member.customer packages_info = order.split_into_packages() for provider_db in packages_info.keys(): package = packages_info[provider_db]['package'] provider_earnings = package.provider_earnings raw_provider_revenue = package.provider_revenue provider_revenue = raw_provider_revenue if package.provider == delcom: provider_revenue += order.delivery_option.cost + order.delivery_option.packing_cost provider_earnings += order.delivery_earnings else: provider_revenue += order.delivery_option.packing_cost provider_earnings += order.delivery_option.packing_cost * (100 - config.ikwen_share_rate) / 100 provider_profile_umbrella = packages_info[provider_db]['provider_profile'] provider_profile_original = provider_profile_umbrella.get_from(provider_db) if provider_profile_original.return_url: nvp_dict = package.get_nvp_api_dict() Thread(target=lambda url, data: requests.post(url, data=data), args=(provider_profile_original.return_url, nvp_dict)).start() if media_order: provider_revenue += media_order.total_cost provider_earnings += media_order.total_cost set_counters(config) increment_history_field(config, 'orders_count_history') increment_history_field(config, 'items_traded_history', order.items_count) increment_history_field(config, 'turnover_history', provider_revenue) increment_history_field(config, 'earnings_history', provider_earnings) set_counters(customer) customer.last_payment_on = datetime.now() increment_history_field(customer, 'orders_count_history') increment_history_field(customer, 'items_purchased_history', order.items_count) increment_history_field(customer, 'turnover_history', provider_revenue) increment_history_field(customer, 'earnings_history', provider_earnings) category_list = [] for entry in order.entries: product = Product.objects.get(pk=entry.product.id) category = product.category turnover = entry.count * product.retail_price set_counters(category) provider_earnings = turnover increment_history_field(category, 'earnings_history', provider_earnings) increment_history_field(category, 'turnover_history', turnover) increment_history_field(category, 'items_traded_history', entry.count) if category not in category_list: increment_history_field(category, 'orders_count_history') category_list.append(category) if update_stock: product.stock -= entry.count if product.stock == 0: add_event(service, SOLD_OUT_EVENT, group_id=sudo_group.id, object_id=product.id) mark_duplicates(product) product.save() set_counters(product) increment_history_field(product, 'units_sold_history', entry.count) for album in media_order.album_list: set_counters(album) increment_history_field(album, 'earnings_history', album.cost) increment_history_field(album, 'turnover_history', album.cost) increment_history_field(album, 'units_sold_history') for song in media_order.song_list: if song.cost == 0: continue set_counters(song) increment_history_field(song, 'earnings_history', song.cost) increment_history_field(song, 'turnover_history', song.cost) increment_history_field(song, 'units_sold_history')