Ejemplo n.º 1
0
def admin_reset_user_pin(user: User):
    pin_reset_token = user.encode_single_use_JWS('R')
    user.save_pin_reset_token(pin_reset_token)
    user.failed_pin_attempts = 0

    pin_reset_message = i18n_for(user, "general_sms.pin_reset")
    send_message(user.phone, pin_reset_message)
Ejemplo n.º 2
0
def send_onboarding_sms_messages(user):

    # First send the intro message
    organisation = getattr(g, 'active_organisation', None) or user.default_organisation

    intro_message = i18n_for(
        user,
        "general_sms.welcome.{}".format(organisation.custom_welcome_message_key or 'generic'),
        first_name=user.first_name,
        balance=rounded_dollars(user.transfer_account.balance),
        token=user.transfer_account.token.name
    )

    send_message(user.phone, intro_message)

    send_terms_message_if_required(user)
Ejemplo n.º 3
0
 def send_sms(self, phone, message_key, **kwargs):
     message = i18n_for(self.user, "ussd.sempo.{}".format(message_key), **kwargs)
     send_message(phone, message)
Ejemplo n.º 4
0
 def send_sms(user, message_key, **kwargs):
     # if we use token processor similarly for other countries later, can generalize country to init
     message = i18n_for(user, "ussd.kenya.{}".format(message_key), **kwargs)
     send_message(user.phone, message)
 def send_sms(self, message_key, **kwargs):
     # if we use directory listing similarly for other countries later, can generalize country to init
     message = i18n_for(self.recipient, "ussd.kenya.{}".format(message_key),
                        **kwargs)
     send_message(self.recipient.phone, message)
Ejemplo n.º 6
0
    def custom_display_text(menu: UssdMenu, ussd_session: UssdSession) -> str:
        """
        Many USSD responses include user-specific data that is stored inside the USSD session. This function
        extracts the appropriate session data based on the current menu name and then inserts them as keywords in the
        i18n function.
        :param menu: The USSD menu to create a text response for
        :param ussd_session: The ussd session containing user data
        :return: raw ussd menu text string
        """

        user = ussd_session.user

        if menu.name == 'about_my_business':
            bio = next(
                filter(lambda x: x.name == 'bio', user.custom_attributes),
                None)
            if bio:
                bio_text = bio.value.strip('"')
            else:
                bio_text = None

            if bio_text is None or '':
                return i18n_for(user, "{}.none".format(menu.display_key))
            else:
                return i18n_for(user,
                                "{}.bio".format(menu.display_key),
                                user_bio=bio_text)

        if menu.name == 'send_token_confirmation':
            recipient = get_user_by_phone(
                ussd_session.get_data('recipient_phone'), should_raise=True)
            recipient_phone = recipient.user_details()
            token = default_token(user)
            transaction_amount = ussd_session.get_data('transaction_amount')
            transaction_reason = ussd_session.get_data(
                'transaction_reason_i18n')
            return i18n_for(
                user,
                menu.display_key,
                recipient_phone=recipient_phone,
                token_name=token.symbol,
                transaction_amount=cents_to_dollars(transaction_amount),
                transaction_reason=transaction_reason)

        if menu.name == 'exchange_token_confirmation':
            agent = get_user_by_phone(ussd_session.get_data('agent_phone'),
                                      should_raise=True)
            agent_phone = agent.user_details()
            token = default_token(user)
            exchange_amount = ussd_session.get_data('exchange_amount')
            return i18n_for(user,
                            menu.display_key,
                            agent_phone=agent_phone,
                            token_name=token.symbol,
                            exchange_amount=cents_to_dollars(exchange_amount))

        # in matching is scary since it might pick up unintentional ones
        if 'exit' in menu.name or 'help' == menu.name:
            return i18n_for(user,
                            menu.display_key,
                            support_phone='+254757628885')

        # in matching is scary since it might pick up unintentional ones
        if 'pin_authorization' in menu.name or 'current_pin' == menu.name:
            if user.failed_pin_attempts is not None and user.failed_pin_attempts > 0:
                return i18n_for(user,
                                "{}.retry".format(menu.display_key),
                                remaining_attempts=3 -
                                user.failed_pin_attempts)
            else:
                return i18n_for(user, "{}.first".format(menu.display_key))

        if menu.name == 'directory_listing' or menu.name == 'send_token_reason':

            blank_template = i18n_for(user, menu.display_key, options='')

            blank_len = len(blank_template)

            most_relevant_usages = ussd_session.get_data(
                'transfer_usage_mapping')

            options = UssdProcessor.fit_usages(ussd_session,
                                               most_relevant_usages, blank_len,
                                               user, 0, [0])

            # current_usages = most_relevant_usages[:ITEMS_PER_MENU]
            return i18n_for(user, menu.display_key, options=options)

        if menu.name == 'directory_listing_other' or menu.name == 'send_token_reason_other':

            most_relevant_usages = ussd_session.get_data(
                'transfer_usage_mapping')
            usage_menu_nr = ussd_session.get_data('usage_menu')
            usage_stack = ussd_session.get_data('usage_index_stack') or [0]

            start_of_list = usage_stack[usage_menu_nr]

            total_usages = len(most_relevant_usages)

            # First see if we can fit remaining usages onto the one page
            if start_of_list + ITEMS_PER_MENU > total_usages:
                part = 'first' if start_of_list == 0 else 'last'
                current_usages = most_relevant_usages[
                    start_of_list:total_usages]
                menu_options = UssdProcessor.create_usages_list(
                    current_usages, user)

                translated_menu = i18n_for(user,
                                           "{}.{}".format(
                                               menu.display_key, part),
                                           other_options=menu_options)

                if len(translated_menu) <= USSD_MAX_LENGTH:
                    return translated_menu

            # Oh well, guess we just have to fit as many as possible then

            part = 'first' if start_of_list == 0 else 'middle'

            blank_template = i18n_for(user,
                                      "{}.{}".format(menu.display_key, part),
                                      other_options='')

            blank_len = len(blank_template)

            options = UssdProcessor.fit_usages(ussd_session,
                                               most_relevant_usages, blank_len,
                                               user, start_of_list,
                                               usage_stack)

            # current_usages = most_relevant_usages[:ITEMS_PER_MENU]
            return i18n_for(user,
                            "{}.{}".format(menu.display_key, part),
                            other_options=options)

        return i18n_for(user, menu.display_key)
Ejemplo n.º 7
0
def send_sms(user, message_key):
    message = i18n_for(user, "user.{}".format(message_key))
    send_message(user.phone, message)
Ejemplo n.º 8
0
def send_terms_message_if_required(user):

    if not user.seen_latest_terms:
        terms_message = i18n_for(user, "general_sms.terms")
        send_message(user.phone, terms_message)
        user.seen_latest_terms = True
Ejemplo n.º 9
0
def menu_display_text_in_lang(current_menu: UssdMenu,
                              user: Optional[User]) -> str:
    return i18n_for(user, current_menu.display_key)
Ejemplo n.º 10
0
    def post(self):
        # Handle a file upload, or CSV in JSON
        if request.files:
            flask_file = request.files['file']
            stream = codecs.iterdecode(flask_file.stream, 'utf-8')
            data = [line for line in stream
                    ]  # Load file into memory to prevent preemptive closing
            reader = csv.DictReader(data)
        else:
            post_data = request.get_json()
            if not post_data:
                response_object = {'message': 'Please provide a CSV file'}
                return make_response(jsonify(response_object)), 400

            csv_data = post_data.get('csv_data', [])
            f = io.StringIO(csv_data)
            reader = csv.DictReader(f)

        transfers = []
        for line in reader:
            tid = line['Transfer ID']
            transfer = db.session.query(CreditTransfer).filter(
                CreditTransfer.id == tid).first()
            message = ''

            if not transfer:
                message = f'Transfer with ID {tid} not found!'
                transfers.append((tid, None, message))
                continue

            if transfer.transfer_type != TransferTypeEnum.WITHDRAWAL:
                message = f'Not a withdrawal!'
                transfers.append((tid, None, message))
                continue

            got_amount = round(dollars_to_cents(line["UnitAmount"]))
            expected_amount = round(transfer.transfer_amount)
            if got_amount != expected_amount:
                message = f'Transfer Amounts do not match (got {cents_to_dollars(got_amount)}, expected {cents_to_dollars(expected_amount)})!'
                transfers.append((tid, None, message))
                continue

            try:
                if line['Payment Has Been Made'].upper(
                ) == 'TRUE' and line['Bank Payment Date']:
                    transfer.add_approver_and_resolve_as_completed()
                    message = 'Transfer Success'
                    if transfer.sender_user.phone and config.PAYOUT_SMS:
                        message = i18n_for(
                            transfer.sender_user,
                            "general_sms.payout_message",
                            first_name=transfer.sender_user.first_name,
                            amount=transfer.rounded_transfer_amount,
                            token=transfer.token.symbol)
                        send_message(transfer.sender_user.phone, message)
                elif line['Payment Has Been Made'] == 'FALSE':
                    transfer.resolve_as_rejected()
                    message = 'Transfer Rejected'
            except Exception as e:
                message = str(e)

            transfers.append((tid, transfer, message))

        output = io.StringIO()
        writer = csv.writer(output)

        writer.writerow([
            'Transfer ID', 'Vendor Account ID', 'Phone', 'First Name',
            'Last Name', 'Transfer Created', 'Transfer Type',
            'Transfer Amount', 'Transfer Status', 'Message'
        ])
        for tid, t, m in transfers:
            writer.writerow([
                tid, t and t.sender_transfer_account.id, t
                and t.sender_transfer_account.primary_user.phone, t
                and t.sender_transfer_account.primary_user.first_name, t
                and t.sender_transfer_account.primary_user.last_name, t
                and t.created, t and t.transfer_type.value, t
                and cents_to_dollars(t.transfer_amount), t
                and t.transfer_status.value, m
            ])
        bytes_output = io.BytesIO()
        bytes_output.write(output.getvalue().encode('utf-8'))
        bytes_output.seek(0)
        return send_file(bytes_output,
                         as_attachment=True,
                         attachment_filename='vendor_payout.csv',
                         mimetype='text/csv')