Exemplo n.º 1
0
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!")
Exemplo n.º 2
0
 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)
Exemplo n.º 3
0
 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()
Exemplo n.º 4
0
class Describe:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.converter = Converter()
        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]
        self.logger.debug(item)

        text_list = list()
        text_list.append(self.converter.get_list_str(item))

        impression = item.get('impression')
        if impression != '':
            text_list.append(f"```\n{impression}\n```")
        else:
            text_list.append("感想は登録されていません。")

        message.send("\n".join(text_list))
Exemplo n.º 5
0
class ListHistory:
    def __init__(self):
        self.logger = get_logger(__name__)
        self.dynamodb = Dynamodb()
        self.converter = Converter()
        self.default_record_num = 20

    def default(self, message):
        items = self.dynamodb.find(self.dynamodb.default_table,
                                   self.default_record_num)
        self.logger.info(items)

        if len(items) == 0:
            message.reply('まだ登録データが無いようです。')
            return

        # 申請日でソート
        items.sort(key=lambda x: x['entry_time'], reverse=True)

        text_list = list()
        for item in items:
            text_list.append(self.converter.get_list_str(item))

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

    def search(self, message, search_words):
        items = self.dynamodb.scan_contains_search_words(search_words)

        if len(items) == 0:
            message.reply('見つかりませんでした...。検索文字を変えてみてください。大文字小文字も区別しますよ。')
            return

        # 申請日でソート
        items.sort(key=lambda x: x['entry_time'], reverse=True)

        text_list = list()
        for item in items:
            text_list.append(self.converter.get_list_str(item))

        message.send("\n".join(text_list))
Exemplo n.º 6
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))
Exemplo n.º 7
0
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))
Exemplo n.º 8
0
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.converter = Converter()
     self.slack = Slack()
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.converter = Converter()
     self.default_record_num = 20
Exemplo n.º 11
0
class Amount:
    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)

    def get_all_total_price_in_year(self, target_yyyy=None) -> int:
        this_year_start, this_year_end = self.converter.get_target_year_start_end(target_yyyy)

        target_entry_time_start = this_year_start.ljust(14, '0')
        target_entry_time_end = this_year_end.ljust(14, '9')
        self.logger.debug(target_entry_time_start)
        self.logger.debug(target_entry_time_end)

        items = self.dynamodb.scan_entry_time(target_entry_time_start, target_entry_time_end)

        all_total_price_in_year = sum(map(lambda x: int(x['book_price']), items))

        return all_total_price_in_year

    def get_total_price_in_this_year(self, slack_name: str) -> int:
        this_year_start, this_year_end = self.converter.get_this_year_from_today()

        target_entry_time_start = this_year_start.ljust(14, '0')
        target_entry_time_end = this_year_end.ljust(14, '9')
        self.logger.debug(target_entry_time_start)
        self.logger.debug(target_entry_time_end)

        items = self.dynamodb.query_entry_time(slack_name, target_entry_time_start, target_entry_time_end)

        total_price_in_this_year = sum(map(lambda x: int(x['book_price']), items))

        return total_price_in_this_year

    def check_max_amount(self, slack_name: str, book_price: str, total_price_in_this_year=None) -> bool:
        if total_price_in_this_year is None:
            total_price_in_this_year = self.get_total_price_in_this_year(slack_name)

        if total_price_in_this_year + int(book_price) > self.max_amount:
            self.logger.info(f"今年度の立替金額が{self.max_amount}円を超えてしまいます 対象ユーザ:{slack_name}, 今年度立替金額合計:{total_price_in_this_year}, 今回立替金額:{book_price}")
            return False

        self.logger.debug(f"対象ユーザ:{slack_name}, 今年度立替金額合計:{total_price_in_this_year}, 今回立替金額:{book_price}")
        return True

    def get_remain_amount(self, slack_name: str, total_price_in_this_year=None) -> int:
        if total_price_in_this_year is None:
            total_price_in_this_year = self.get_total_price_in_this_year(slack_name)

        remain_amount = self.max_amount - total_price_in_this_year

        # もしマイナスになったら0にしておく
        if remain_amount < 0:
            remain_amount = 0

        return remain_amount
Exemplo n.º 12
0
 def __init__(self):
     self.logger = get_logger(__name__)
     self.amount = Amount()
     self.converter = Converter()
     self.slack = Slack()
Exemplo n.º 13
0
import pytest
from datetime import datetime
from lib.util.converter import Converter

target = Converter()


def test_to_hankaku():
    assert target.to_hankaku('ABCDE') == 'ABCDE'
    assert target.to_hankaku(' あいうえお 0123456789') == ' あいうえお 0123456789'


def test_get_this_year_from_today():
    assert target.get_this_year_from_today(
        datetime.strptime('2019-04-01',
                          '%Y-%m-%d')) == ('20190401', '20190401')
    assert target.get_this_year_from_today(
        datetime.strptime('2019-03-31',
                          '%Y-%m-%d')) == ('20180401', '20190331')
    assert target.get_this_year_from_today(
        datetime.strptime('2019-05-01',
                          '%Y-%m-%d')) == ('20190401', '20190501')
    assert target.get_this_year_from_today(
        datetime.strptime('2019-01-01',
                          '%Y-%m-%d')) == ('20180401', '20190101')
    assert target.get_this_year_from_today(
        datetime.strptime('2020-02-29',
                          '%Y-%m-%d')) == ('20190401', '20200229')


def test_get_date_str():
Exemplo n.º 14
0
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)
Exemplo n.º 15
0
 def __init__(self):
     self.logger = get_logger(__name__)
     self.dynamodb = Dynamodb()
     self.converter = Converter()
     self.list_history = ListHistory()