Python中級 - 解答

Python中級のチャレンジ

そこそこ複雑な注文集計処理を作る演習問題 - 1問目

main.py の1問目終了時の解答コードです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from datetime import date
import os

ITEM_TSV_PATH = 'items.tsv'
ORDER_DIR = 'order/'
FAILURE_DIR = 'failure/'
DELIVERY_DIR = 'delivery/'


class Item:
    """ 1商品に対応するクラス
    """
    def __init__(self, item_id, name, price):
        self.item_id = item_id
        self.name = name
        self.price = price


class Items:
    def __init__(self, items):
        self.items = items

    def has_id(self, item_id):
        """ item_id をもつ商品が存在するかチェックする
        """
        for item in self.items:
            if item.item_id == item_id:
                return True
        return False


class Order:
    def __init__(self, item_id, amount, shipping_address, tel_number,
                 fullname, shipping_date_str, order_file):
        self.item_id = item_id
        self.amount = amount
        self.shipping_address = shipping_address
        self.tel_number = tel_number
        self.fullname = fullname
        self.shipping_date_str = shipping_date_str
        self.order_file = order_file

        self.amount_int = None
        self.shipping_date = None

    def validate(self, items):
        """ 各注文の値が正しいかバリデーションチェックする。OKの場合True、NGの場合False
        """

    def row_string(self):
        return ','.join((
            self.item_id,
            self.amount,
            self.shipping_address,
            self.tel_number,
            self.fullname,
            self.shipping_date_str,
            self.order_file,
        ))


def load_items():
    """ ITEM_TSV_PATHのTSVからItemsを作る
    """
    items = []
    with open(ITEM_TSV_PATH, encoding='utf-8') as f:
        for row in f:
            item_id, name, price = row.split('\t')
            item = Item(item_id.strip(), name.strip(), price.strip())
            items.append(item)
    return Items(items)


def load_orders(target_date):
    """ ORDER_DIR のCSVからOrderのリストを作る

    * 各値の前後から空白を除外する
    """


def write_deliver_orders(orders):
    """ Orderのリストを受け取って日別注文ファイルに書き込み
    """
    # 宅配日毎に集計。ファイルをオープンする回数を減らすため事前にまとめる
    date_orders = {}
    for order in orders:
        if order.shipping_date in date_orders:
            date_orders[order.shipping_date].append(order)
        else:
            date_orders[order.shipping_date] = [order]

    for d, day_orders in date_orders.items():
        filename = 'delivery_{}.csv'.format(d.strftime('%Y%m%d'))
        filepath = os.path.join(DELIVERY_DIR, filename)
        with open(filepath, 'a', encoding='utf-8') as f:
            for order in day_orders:
                f.write(order.row_string() + '\n')


def write_failure_orders(orders, order_date):
    """ Orderのリストを受け取って注文受付失敗ファイルに書き込み
    """


def main(target_date=None):
    """ 毎日の注文集計用スクリプト

    1. 商品マスター読み込み
    2. 当日分の注文受付ファイル読み込み
    3. 注文をバリデーションチェック
    4. 日別注文ファイル書き込み
    5. 注文受付失敗ファイル書き込み
    """
    target_date = target_date or date.today()

    items = load_items()
    orders = load_orders(target_date)
    validated_orders = []
    failed_orders = []
    for order in orders:
        if order.validate(items):
            validated_orders.append(order)
        else:
            failed_orders.append(order)

    if validated_orders:
        write_deliver_orders(validated_orders)
    if failed_orders:
        write_failure_orders(failed_orders, target_date)


if __name__ == '__main__':
    main(date(2016, 12, 14))  # あくまで動作確認用に日付を指定している