コード例 #1
0
ファイル: reminder.py プロジェクト: sticker/bookbot
class Reminder:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.converter = Converter()
        self.slack = Slack()

    def remind_impression(self, elapsed_days=60):
        self.logger.info(f"感想登録されずに{elapsed_days}日経過したのでリマインドをします")
        target_entry_time_yyyymmdd = self.converter.get_yyyymmdd_specified_days_ago(days_ago=elapsed_days)
        self.logger.debug(f"target_entry_time_yyyymmdd={target_entry_time_yyyymmdd}")
        items = self.dynamodb.query_impression_flag_and_entry_time("0", target_entry_time_yyyymmdd)

        if len(items) == 0:
            self.logger.info(f"リマインド対象者はいませんでした")
            return

        mention_set = set()
        book_list = list()
        for item in items:
            mention_set.add(f"<@{item['slack_id']}>")
            book_list.append(self.converter.get_list_str(item))

        text_list = list()
        text_list.append(" ".join(mention_set) + " そろそろ読み終わりましたか?読み終わったら感想登録お願いします!")
        text_list.extend(book_list)
        channel_name = self.slack.get_channel_name_by_slacker(settings.DEFAULT_CHANNEL_ID)
        self.slack.send_message_by_slacker(channel=channel_name, text="\n".join(text_list))

        return True

    def remind_impression_minutes(self):
        self.logger.info("remind minutes!")
コード例 #2
0
ファイル: entry.py プロジェクト: sticker/bookbot
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.s3 = S3()
     self.amount = Amount()
     self.converter = Converter()
     self.validation = Validation()
     self.slack = Slack()
     self.pdf = Pdf()
コード例 #3
0
ファイル: bookbot.py プロジェクト: sticker/bookbot
def delete_handler(message: Message, command, entry_no):
    logging.info(message.body)

    if message.body['channel'] != settings.DEFAULT_CHANNEL_ID:
        slack = Slack()
        text = f"公式チャンネル #{slack.get_channel_name(message, channel_id=settings.DEFAULT_CHANNEL_ID)} で実行してください!"
        slack.send_message_with_link_names(message, message.body['channel'],
                                           text)
        return

    if entry_no is None or entry_no == '':
        message.send(f"{command} のあとに登録番号(半角数字のみ)を入力してください")
        return

    Delete().specified_entry_no(message, entry_no)
コード例 #4
0
ファイル: amount.py プロジェクト: sticker/bookbot
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.s3 = S3()
     self.converter = Converter()
     self.validation = Validation()
     self.slack = Slack()
     # 年間上限金額
     self.max_amount = int(settings.MAX_AMOUNT)
コード例 #5
0
class Total:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.amount = Amount()
        self.converter = Converter()
        self.slack = Slack()

    def default(self, message):
        # 申請者 Slack ID
        slack_id = self.slack.get_slack_id(message)
        # 申請者名
        user_name = self.slack.get_user_name(slack_id, message)
        slack_name = user_name[0]

        total_price_in_this_year = self.amount.get_total_price_in_this_year(slack_name)
        remain_amount = self.amount.get_remain_amount(slack_name)

        text_list = list()
        text_list.append(f"今年度の立替金合計は *{total_price_in_this_year}* 円 です。")
        if remain_amount == 0:
            text_list.append(f"上限金額は *{self.amount.max_amount}* 円です。今年度はこれ以上立替できません。")
        else:
            text_list.append(f"残り *{remain_amount}* 円 までならOKです。")

        message.reply("\n".join(text_list))

    def all_total_price_in_year(self, message, target_yyyy):
        text_list = list()
        self.logger.debug(len(target_yyyy))
        if len(target_yyyy) == 4:
            all_total_price_in_year = self.amount.get_all_total_price_in_year(target_yyyy)
            text_list.append(f"{target_yyyy}年度のすべての立替金合計は *{all_total_price_in_year}* 円 です。")
        else:
            this_year_start, this_year_end = self.converter.get_this_year_from_today()
            target_yyyy = this_year_start[0:4]
            all_total_price_in_year = self.amount.get_all_total_price_in_year(target_yyyy)
            text_list.append(f"今年度のすべての立替金合計は *{all_total_price_in_year}* 円 です。")

        message.reply("\n".join(text_list))
コード例 #6
0
ファイル: delete.py プロジェクト: sticker/bookbot
class Delete:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.converter = Converter()
        self.slack = Slack()
        self.list_history = ListHistory()

    def specified_entry_no(self, message, entry_no):
        # 削除対象レコードを取得
        items = self.dynamodb.query_specified_key_value(
            self.dynamodb.default_table, 'entry_no', entry_no)
        if len(items) == 0:
            message.reply(f"登録番号 *[{entry_no}]* のデータが見つかりません。")
            return

        # プライマリキー指定なので必ず1件取得
        item = items[0]

        # 削除できるのは自分の登録情報だけ
        if item['slack_id'] != self.slack.get_slack_id(message):
            message.reply("削除できるのは自分の登録情報だけです!")
            return

        # 感想登録されていたら削除不可とする
        if item['impression_flag'] == '1':
            message.reply("感想登録後は削除できません!")
            return

        # レコード削除
        key = dict()
        key['entry_no'] = entry_no
        self.dynamodb.remove(self.dynamodb.default_table, key)

        text_list = list()
        text_list.append("以下の登録情報を削除しました!")
        text_list.append(self.converter.get_list_str(item))

        message.reply("\n".join(text_list))
コード例 #7
0
ファイル: reminder.py プロジェクト: sticker/bookbot
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.converter = Converter()
     self.slack = Slack()
コード例 #8
0
ファイル: impression.py プロジェクト: sticker/bookbot
class Impression:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.converter = Converter()
        self.validation = Validation()
        self.slack = Slack()

    def save(self, message: Message):
        now = datetime.now()

        entry_no = ''
        impression = ''
        for block in message.body['blocks']:
            if not ('text' in block and 'text' in block['text']):
                continue

            text = block['text']['text']
            if '*登録番号*' in text:
                entry_no = re.sub('\\D', '', self.converter.to_hankaku(text))
                self.logger.debug(f"entry_no={entry_no}")
            elif '*感想*' in text:
                impression = re.sub('\*感想\*\n', '', text).strip()
                self.logger.debug(f"impression={impression}")

        # 投稿タイムスタンプ(スレッド投稿のため)
        ts = message.body['ts']

        # パラメータチェック
        if not self.validation.validate_impression(entry_no=entry_no, message=message):
            self.logger.debug("パラメータチェックNG")
            return

        # 申請者 Slack ID
        slack_id = self.slack.get_slack_id_from_workflow(message.body['text'])

        # 更新対象レコードを取得
        items = self.dynamodb.query_specified_key_value(self.dynamodb.default_table, 'entry_no', entry_no)
        # プライマリキー指定なので必ず1件取得
        item = items[0]

        if item['slack_id'] != slack_id:
            message.send(f"<@{slack_id}> 購入者本人以外は感想登録できません!", thread_ts=ts)
            return False

        # 感想登録日
        impression_time = now.strftime("%Y%m%d%H%M%S")
        self.logger.debug(f"impression_time={impression_time}")

        # 感想登録フラグ 1:登録あり
        impression_flag = '1'

        # 感想登録
        response = self.dynamodb.update_bookbot_entry_impression(entry_no, impression, impression_time, impression_flag)
        self.logger.debug(response)
        if response is None:
            self.logger.error(f"感想の登録に失敗しました")
            message.send(f"<@{slack_id}> 感想の登録に失敗しました...すいません!", thread_ts=ts)
            return False

        item['impression'] = impression
        reply_texts = [f"<!here> 以下の感想が登録されました!"]
        reply_texts.append(self.converter.get_list_str(item))

        message.send("\n".join(reply_texts), thread_ts=ts)
コード例 #9
0
 def __init__(self):
     self.logger = get_logger(__name__)
     self.amount = Amount()
     self.converter = Converter()
     self.slack = Slack()
コード例 #10
0
ファイル: entry.py プロジェクト: sticker/bookbot
class Entry:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.s3 = S3()
        self.amount = Amount()
        self.converter = Converter()
        self.validation = Validation()
        self.slack = Slack()
        self.pdf = Pdf()

    def save(self, message: Message):

        now = datetime.now()

        book_name = ''
        book_type = ''
        book_price = ''
        book_url = ''
        purpose = ''
        for block in message.body['blocks']:
            if not ('text' in block and 'text' in block['text']):
                continue

            text = block['text']['text']
            if '*題名*' in text:
                book_name = re.sub('\*題名\*|\n', '', text)
                self.logger.debug(f"book_name={book_name}")
            elif '*形式*' in text:
                book_type = re.sub('\*形式\*|\n', '', text)
                self.logger.debug(f"book_type={book_type}")
            elif '*立替金額(税込)*' in text:
                book_price = re.sub('\\D', '', self.converter.to_hankaku(text))
                self.logger.debug(f"book_price={book_price}")
            elif '*詳細リンク(Amazonなど)*' in text:
                book_url = re.sub('\*詳細リンク(Amazonなど)\*|<|>|\n', '', text)
                self.logger.debug(f"book_url={book_url}")
            elif '*購入目的*' in text:
                purpose = re.sub('\*購入目的\*|<|>|\n', '', text)
                self.logger.debug(f"purpose={purpose}")

        # 投稿タイムスタンプ(スレッド投稿のため)
        ts = message.body['ts']

        # パラメータチェック
        if not self.validation.validate_entry(book_name=book_name, book_price=book_price, book_url=book_url, message=message):
            self.logger.debug("パラメータチェックNG")
            return

        # 申請日
        entry_time = now.strftime("%Y%m%d%H%M%S")

        # 申請者 Slack ID
        slack_id = self.slack.get_slack_id_from_workflow(message.body['text'])

        # 申請者名
        user_name = self.slack.get_user_name(slack_id, message)
        slack_name = user_name[0]
        real_name = user_name[1]

        # 今年度の合計立替金額を取得
        total_price_in_this_year = self.amount.get_total_price_in_this_year(slack_name)
        # そのユーザが年間上限金額以上立替していないか
        result = self.amount.check_max_amount(slack_name, book_price, total_price_in_this_year)
        # 今回申請分を登録する前の 残り金額
        remain_amount = self.amount.get_remain_amount(slack_name, total_price_in_this_year)
        if not result:
            self.logger.debug("年間立替金額上限を超えています")
            message.send(f"<@{slack_id}> 年間立替金額上限を超えるため登録できません。残り *{remain_amount}* 円 までならOKです。", thread_ts=ts)
            return

        # 受付番号
        # アトミックカウンタでシーケンス番号を発行し文字列として取得する
        entry_no = str(self.dynamodb.atomic_counter('atomic-counter', 'entry_no'))

        # 今年度の合計立替金額に今回申請分を足す
        total_price_in_this_year += int(book_price)
        # 今回申請分を登録した後の 残り金額
        remain_amount = self.amount.get_remain_amount(slack_name, total_price_in_this_year)

        # パーマリンクを取得
        permalink = self.slack.get_message_permalink(message)

        # 感想(空で登録)
        impression = ''
        impression_flag = '0'  # 0:登録無し

        item = {
            'entry_no': entry_no,
            'book_name': book_name,
            'book_type': book_type,
            'book_price': book_price,
            'total_price_in_this_year': total_price_in_this_year,
            'remain_amount': remain_amount,
            'book_url': book_url,
            'purpose': purpose,
            'entry_time': entry_time,
            'slack_id': slack_id,
            'slack_name': slack_name,
            'real_name': real_name,
            'permalink': permalink,
            'impression': impression,
            'impression_flag': impression_flag
        }
        self.logger.info(f"item={item}")

        self.dynamodb.insert(self.dynamodb.default_table, item)

        reply_texts = [f"<@{slack_id}> 登録しました!"]
        reply_texts.append(f"登録番号: *[{entry_no}]*")
        reply_texts.append(f"今年度の立替金額合計が *{total_price_in_this_year}* 円になりました。")
        if remain_amount == 0:
            reply_texts.append(f"上限金額は *{self.amount.max_amount}* 円です。今年度はこれが最後の立替になります。")
        else:
            reply_texts.append(f"残り *{remain_amount}* 円 までならOKです。")

        if book_price == '0':
            self.logger.info("0円のため承認PDFは作成しません")
            message.send("\n".join(reply_texts), thread_ts=ts)
            return

        reply_texts.append('補助対象になりますので承認PDFを作成します。')
        message.send("\n".join(reply_texts), thread_ts=ts)

        # 承認内容のPDFを作成してSlackにアップ バックアップでS3にアップ
        # 保存先PDFファイルパス
        save_pdf_fname = f"{entry_no}_{entry_time}_{slack_name}.pdf"
        save_pdf_path = f"{app_home}/output_pdf/{save_pdf_fname}"
        # 承認PDF作成
        if not self.pdf.make_approved_pdf(item, save_pdf_path):
            self.logger.warning('承認PDFの作成に失敗しました')
            message.send(f"<@{item['slack_id']}> 承認PDFの作成に失敗しました...すいません!")
            return False

        channel_name = self.slack.get_channel_name(message)
        self.logger.debug(channel_name)

        self.slack.upload_file(message, channel_name,
                               fpath=save_pdf_path,
                               comment="このPDFと購入時の領収書を添付して立替金申請をしてください。",
                               thread_ts=ts)

        # S3にもアップロード
        this_year = self.converter.get_this_year_from_today()[0][0:4]  # 今年度のYYYY
        self.s3.upload_to_pdf(save_pdf_path, process_yyyy=this_year)