예제 #1
0
    def post(self):
        self.set_header("Content-Type", "application/json")

        ret = {}

        date        = self.get_argument('date')
        master_id   = self.get_argument('master_id', '')

        # convert arguments
        date = dt.datetime.strptime(date, '%Y%m%d')

        try:
            session = Session()
            userdao = UserDAO()

            result = session.query(Booking, User, UserAddress) \
                            .join(User, Booking.user_id == User.id) \
                            .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                            .filter(Booking.master_id == master_id) \
                            .filter(func.date(Booking.start_time) == date) \
                            .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED, Booking.cleaning_status == BC.BOOKING_COMPLETED)) \
                            .order_by(Booking.start_time) \
                            .all()

            booking_list = []

            for row in result:
                key = userdao.get_user_salt_by_id(row.Booking.user_id)[:16]
                crypto = aes.MyCrypto(key)

                booking = {}

                tooktime = time_to_minutes(timedelta_to_time(row.Booking.estimated_end_time - row.Booking.start_time))

                if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                    if row.Booking.is_dirty == 1:
                        tooktime -= 120

                start_time = row.Booking.start_time

                request_count = session.query(MasterBookingModifyRequest) \
                        .filter(MasterBookingModifyRequest.master_id == master_id) \
                        .filter(MasterBookingModifyRequest.booking_id == row.Booking.id) \
                        .filter(MasterBookingModifyRequest.org_time == start_time) \
                        .count()

                booking['booking_id']       = row.Booking.id
                booking['start_time']       = convert_time_format(row.Booking.start_time.time())
                booking['name']             = crypto.decodeAES(row.User.name)
                booking['address']          = crypto.decodeAES(row.UserAddress.address)
                #booking['jibun_address']    = convert_to_jibun_address(booking['address'])
                booking['size']             = row.UserAddress.size
                booking['kind']             = row.UserAddress.kind
                booking['additional_task']  = row.Booking.additional_task
                booking['appointment_type'] = row.Booking.appointment_type
                booking['index']            = row.Booking.appointment_index
                booking['tooktime']         = int(tooktime / 6)
                booking['status']           = row.Booking.status
                booking['cleaning_status']  = row.Booking.cleaning_status
                booking['payment_status']   = row.Booking.payment_status
                booking['is_dirty']         = row.Booking.is_dirty
                booking['request_modify']   = request_count

                booking_list.append(booking)

            dayoff       = False
            is_open_time = False
            free_from    = None
            free_to      = None

            row = session.query(MasterScheduleByDate) \
                    .filter(MasterScheduleByDate.master_id == master_id) \
                    .filter(MasterScheduleByDate.date == date) \
                    .first()

            if row != None:
                if row.active == 0:
                    dayoff = True

                is_open_time = True
                free_from = row.free_from.strftime('%H:%M')
                free_to   = row.free_to.strftime('%H:%M')


            ret['response'] = {'booking_list' : booking_list, 'free_from' : free_from, 'free_to' : free_to, 'is_open_time' : is_open_time, 'dayoff' : dayoff}
            self.set_status(Response.RESULT_OK)

        except Exception, e:
            session.rollback()

            print_err_detail(e)
            self.set_status(Response.RESULT_SERVERERROR)
            add_err_message_to_response(ret, err_dict['err_mysql'])
class EditBookingHandler(tornado.web.RequestHandler):
    def post(self):
        self.set_header("Content-Type", "application/json")

        booking_id = self.get_argument('booking_id', '')
        changed = self.get_argument('ischange', '')
        date = self.get_argument('date', dt.datetime.now())
        start_time_range_begin = self.get_argument('range_begin',
                                                   BC.START_TIME_RANGE_BEGIN)
        start_time_range_begin_min = self.get_argument('range_begin_min', 0)
        start_time_range_end = self.get_argument('range_end',
                                                 BC.START_TIME_RANGE_END)
        start_time_range_end_min = self.get_argument('range_end_min', 0)
        price = self.get_argument('price', 0)
        taking_time = self.get_argument('taking_time', 25)
        additional_task = self.get_argument('additional_task', 0)
        message = self.get_argument('msg', '')
        laundry_apply_all = self.get_argument(
            'laundry_apply_all', 0)  # -1 - 없앰, 0 - one time, 1 - all time

        print 'edit booking params....'
        print booking_id, changed, date, additional_task, taking_time, price
        # convert datetime

        price = int(price)
        taking_time = int(taking_time)
        additional_task = int(additional_task)
        taking_time_in_minutes = taking_time * 6
        laundry_apply_all = int(laundry_apply_all)

        changed = "{0:03b}".format(int(changed))

        mongo_logger = get_mongo_logger()

        mongo_logger.debug('%s was called to updated' % booking_id,
                           extra={
                               'changed': changed,
                               'date': date,
                               'start_time_range_begin':
                               start_time_range_begin,
                               'start_time_range_end': start_time_range_end,
                               'price': price,
                               'taking_time': taking_time,
                               'additional_task': additional_task,
                               'user_message': message
                           })

        ret = {}

        mix = get_mixpanel()

        try:
            session = Session()

            userdao = UserDAO()
            addrdao = AddressDAO()
            masterdao = MasterDAO()

            try:
                row = session.query(Booking).filter(
                    Booking.id == booking_id).one()
            except NoResultFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_no_record'])
                return

            except MultipleResultsFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret,
                                            err_dict['err_multiple_record'])
                return

            uid = row.user_id
            price_with_task = row.price_with_task
            appointment_type = row.appointment_type
            org_master_id = row.master_id

            holder = IntermediateValueHolder()

            org_date = dt.datetime.strftime(row.start_time, '%m월%d일')

            time_changed = changed[2]
            task_changed = changed[1]
            msg_changed = changed[0]

            # booking can not be updated within 24 hours ahead
            appointment_time = row.start_time
            current_time = dt.datetime.now()
            diff_in_hours = (appointment_time -
                             current_time).total_seconds() / 3600

            if diff_in_hours < 24:  # 못바꾸도록 함
                time_changed = 0
                task_changed = 0

            havetools = 1
            if additional_task >= 64:
                havetools = 0

            # time이 변경되었다면 무조건 scheduling
            if time_changed == '1':
                date = dt.datetime.strptime(date, '%Y%m%d')
                start_time_range_begin = int(start_time_range_begin)
                start_time_range_begin_min = int(start_time_range_begin_min)
                start_time_range_end = int(start_time_range_end)
                start_time_range_end_min = int(start_time_range_end_min)

                appointment_type = 0  # 여기서는 1회 청소로 한다. 편집이기 때문에
                start_time = row.start_time
                end_time = row.estimated_end_time
                have_pet = row.havepet
                master_gender = row.master_gender
                price_with_task = row.price_with_task
                addr_idx = row.addr_idx

                org_taking_time_in_minutes = time_to_minutes(
                    timedelta_to_time(end_time - start_time))
                new_taking_time_in_minutes = org_taking_time_in_minutes + taking_time_in_minutes

                address, geohash5, geohash6 = userdao.get_user_address_by_index(
                    uid, addr_idx)
                gu_id = addrdao.get_gu_id(address)
                dates = [int(dt.datetime.strftime(date, '%Y%m%d'))]

                schedule_by_date_list = masterdao.get_master_schedule_by_dates(
                    gu_id, have_pet, master_gender, dates)
                success, msg, store_key, search_keys, result = masterdao.find_master_by_score(schedule_by_date_list, \
                                                    gu_id, \
                                                    uid, \
                                                    appointment_type, \
                                                    dates, \
                                                    start_time_range_begin, \
                                                    start_time_range_begin_min, \
                                                    start_time_range_end, \
                                                    start_time_range_end_min, \
                                                    new_taking_time_in_minutes, \
                                                    geohash6)

                # if not successful
                if success != 'SUCCESS':
                    session.close()
                    self.set_status(Response.RESULT_OK)
                    add_err_message_to_response(
                        ret, err_dict['err_no_hm_at_that_time'])
                    self.write(json.dumps(ret))
                    return

                else:  # find matching homemaster
                    item = result[0]

                    master_id = item['mid']
                    dow = dt.datetime.strptime(item['date'],
                                               '%Y%m%d').date().weekday()
                    start_time = dt.datetime.combine(
                        dt.datetime.strptime(item['date'], '%Y%m%d'),
                        item['start_time'])
                    estimated_end_time = dt.datetime.combine(
                        dt.datetime.strptime(item['date'], '%Y%m%d'),
                        item['end_time'])

                    status = row.payment_status
                    if status == BC.BOOKING_PAID:  # 미리 지불한 경우는 취소 하고 다시 결제함
                        # 전거래 취소 및 재결제
                        cancel_ret_code, msg = cancel_payment(uid,
                                                              booking_id,
                                                              price_with_task,
                                                              partial='0')
                        if cancel_ret_code:
                            user_name = userdao.get_user_name(uid)
                            pay_ret_code, pay_msg = request_payment(
                                uid,
                                user_name,
                                booking_id,
                                price,
                                appointment_type,
                                status='UPDATED')
                            if pay_ret_code:
                                row.tid = pay_msg
                                row.payment_status = BC.BOOKING_PAID
                            else:
                                row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                session.commit()
                                session.close()
                                self.set_status(Response.RESULT_OK)
                                add_err_ko_message_to_response(ret, pay_msg)
                                self.write(json.dumps(ret))
                                return

                    row.master_id = master_id
                    row.dow = dow
                    row.price_with_task = price
                    row.start_time = start_time
                    row.message = message
                    row.additional_task = additional_task
                    row.havetools = havetools
                    row.estimated_end_time = estimated_end_time
                    row.laundry_apply_all = laundry_apply_all

                    if org_master_id != master_id:
                        row.is_master_changed = 1

                    # about laundry
                    request_id = row.request_id
                    appointment_index = row.appointment_index

                    all_bookings = session.query(Booking) \
                            .filter(Booking.request_id == request_id) \
                            .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                            .filter(Booking.appointment_index > appointment_index) \
                            .all()

                    if laundry_apply_all == 1:
                        for booking in all_bookings:
                            booking.additional_task += 4  # 빨래
                            booking.laundry_apply_all = laundry_apply_all
                    else:
                        for booking in all_bookings:
                            bits = "{0:07b}".format(booking.additional_task)
                            if bits[4] == '1':
                                booking.additional_task -= 4  # 빨래 제거
                            booking.laundry_apply_all = laundry_apply_all

                    session.commit()

                    holder.remove(store_key)
                    for sk in search_keys:
                        holder.remove(sk)

            else:
                if task_changed == '1':
                    if taking_time_in_minutes > 0:  # 실제 시간이 늘어났을 경우에만 뒷 스케쥴 확인

                        master_id, start_date_int = masterdao.get_masterid_and_starttime_from_booking(
                            booking_id)
                        search_key = '%s_%d' % (master_id, start_date_int)

                        new_estimated_end_time = masterdao.is_master_available_next_schedule(
                            booking_id, taking_time_in_minutes)
                        print new_estimated_end_time, '&&&&'

                        if new_estimated_end_time != None and holder.store(
                                search_key, 1):  # 실제로 시간이 가능하면
                            status = row.payment_status
                            if status == BC.BOOKING_PAID:  # 미리 지불한 경우는 취소 하고 다시 결제함
                                # 전거래 취소 및 재결제
                                cancel_ret_code, msg = cancel_payment(
                                    uid,
                                    booking_id,
                                    price_with_task,
                                    partial='0')
                                if cancel_ret_code:
                                    user_name = userdao.get_user_name(uid)
                                    pay_ret_code, pay_msg = request_payment(
                                        uid,
                                        user_name,
                                        booking_id,
                                        price,
                                        appointment_type,
                                        status='UPDATED')
                                    if pay_ret_code:
                                        row.tid = pay_msg
                                        row.payment_status = BC.BOOKING_PAID
                                    else:
                                        row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                        session.commit()
                                        session.close()
                                        self.set_status(Response.RESULT_OK)
                                        add_err_ko_message_to_response(
                                            ret, pay_msg)
                                        self.write(json.dumps(ret))
                                        return

                            row.estimated_end_time = new_estimated_end_time
                            row.additional_task = additional_task
                            row.message = message
                            row.price_with_task = price
                            row.havetools = havetools
                            row.laundry_apply_all = laundry_apply_all

                            # about laundry
                            request_id = row.request_id
                            appointment_index = row.appointment_index

                            all_bookings = session.query(Booking) \
                                    .filter(Booking.request_id == request_id) \
                                    .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                                    .filter(Booking.appointment_index > appointment_index) \
                                    .all()

                            if laundry_apply_all == 1:
                                for booking in all_bookings:
                                    booking.additional_task += 4  # 빨래
                                    booking.laundry_apply_all = laundry_apply_all
                            else:
                                for booking in all_bookings:
                                    bits = "{0:07b}".format(
                                        booking.additional_task)
                                    if bits[4] == '1':
                                        booking.additional_task -= 4  # 빨래 제거
                                    booking.laundry_apply_all = laundry_apply_all

                            session.commit()

                            # 메모리에서 삭제
                            holder.remove(search_key)

                        else:  # 스케쥴이 있어서 불가능 함
                            session.close()
                            self.set_status(Response.RESULT_OK)
                            add_err_message_to_response(
                                ret, err_dict['err_hm_have_next_schedule'])
                            self.write(json.dumps(ret))
                            return
                    else:  # 시간이 줄어들었거나, 그대로인경우에는 additional task 값만 바꾸면 됨
                        status = row.payment_status
                        if status == BC.BOOKING_PAID:  # 미리 지불한 경우는 취소 하고 다시 결제함
                            # 전거래 취소 및 재결제
                            cancel_ret_code, msg = cancel_payment(
                                uid, booking_id, price_with_task, partial='0')
                            if cancel_ret_code:
                                user_name = userdao.get_user_name(uid)
                                pay_ret_code, pay_msg = request_payment(
                                    uid,
                                    user_name,
                                    booking_id,
                                    price,
                                    appointment_type,
                                    status='UPDATED')
                                if pay_ret_code:
                                    row.tid = pay_msg
                                    row.payment_status = BC.BOOKING_PAID
                                else:
                                    row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                    session.commit()
                                    session.close()
                                    self.set_status(Response.RESULT_OK)
                                    add_err_ko_message_to_response(
                                        ret, pay_msg)
                                    self.write(json.dumps(ret))
                                    return

                        print row.estimated_end_time, taking_time_in_minutes
                        row.estimated_end_time = row.estimated_end_time + dt.timedelta(
                            minutes=taking_time_in_minutes)
                        row.additional_task = additional_task
                        row.message = message
                        row.price_with_task = price
                        row.havetools = havetools
                        row.laundry_apply_all = laundry_apply_all

                        # about laundry
                        request_id = row.request_id
                        appointment_index = row.appointment_index

                        all_bookings = session.query(Booking) \
                                .filter(Booking.request_id == request_id) \
                                .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                                .filter(Booking.appointment_index > appointment_index) \
                                .all()

                        if laundry_apply_all == 1:
                            for booking in all_bookings:
                                booking.additional_task += 4  # 빨래
                                booking.laundry_apply_all = laundry_apply_all
                        else:
                            for booking in all_bookings:
                                bits = "{0:07b}".format(
                                    booking.additional_task)
                                if bits[4] == '1':
                                    booking.additional_task -= 4  # 빨래 제거
                                booking.laundry_apply_all = laundry_apply_all

                        session.commit()
                else:
                    row.message = message
                    session.commit()

            # 문자 전송
            #send_updated_text(booking_id, org_date)

            ret['response'] = Response.SUCCESS
            self.set_status(Response.RESULT_OK)

            mix.track(
                uid, 'update', {
                    'time': dt.datetime.now(),
                    'booking_id': booking_id,
                    'additional_task': additional_task
                })
            mongo_logger.debug('%s was updated' % booking_id,
                               extra={
                                   'user_id': uid,
                                   'booking_id': booking_id
                               })
            print booking_id, 'successfully updated...'
예제 #3
0
class RequestAvailableSchedulesForChangeCircleHandler(
        tornado.web.RequestHandler):
    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        ret = {}

        booking_id = self.get_argument('booking_id', '')
        appointment_type = self.get_argument('appointment_type', 0)
        is_admin = self.get_argument('is_admin', 1)

        appointment_type = int(appointment_type)
        is_admin = int(is_admin)

        print 'appointment_type', appointment_type

        # logging part
        mix = get_mixpanel()
        mongo_logger = get_mongo_logger()

        try:
            session = Session()
            try:
                row = session.query(Booking).filter(
                    Booking.id == booking_id).one()
            except NoResultFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_no_record'])
                return

            except MultipleResultsFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret,
                                            err_dict['err_multiple_record'])
                return

            uid = row.user_id
            have_pet = row.havepet
            master_gender = row.master_gender
            isdirty = row.is_dirty
            start_time = row.start_time
            estimated_end_time = row.estimated_end_time
            appointment_date = row.org_start_time
            request_id = row.request_id
            addr_idx = row.addr_idx

            print "orginal apointment type : " + str(row.appointment_type)

            total_taking_time_in_minutes = time_to_minutes(
                timedelta_to_time(estimated_end_time - start_time))

            scheduler = HMScheduler()

            userdao = UserDAO()
            addrdao = AddressDAO()
            address, geohash5, geohash6 = userdao.get_user_address_by_index(
                uid, addr_idx)  # 편집의 경우에는, 예약된 주소를 이용한다.
            gu_id = addrdao.get_gu_id(address)

            if gu_id == '':
                raise Exception('gu id is incorrect')

            update = True
            available_schedules = scheduler.get_available_slots(
                gu_id=gu_id,
                geohash=geohash6,
                appointment_type=appointment_type,
                taking_time=total_taking_time_in_minutes,
                prefer_women=True if master_gender == 1 else False,
                have_pet=True if have_pet == 1 else False,
                isdirty=True if isdirty == 1 else False,
                user_id=uid)

            if is_admin == 0:  # is_admin == False
                now = dt.datetime.now()
                if now.hour >= 17:  # 7시 이후 라면 -> 5시로 변경
                    tomorrow = now + dt.timedelta(days=1)
                    tomorrow = dt.datetime.strftime(tomorrow, '%Y%m%d')
                    if tomorrow in available_schedules:
                        del available_schedules[tomorrow]

            for day in available_schedules:
                print '[', day, ']'
                print available_schedules[day]['by_time']
            print 'schdules for update...'

            print 'have_pet', have_pet
            print 'master_gender', master_gender
            print 'isdirty', isdirty
            print 'taking_time', total_taking_time_in_minutes
            print 'appointment_date', appointment_date
            print 'gu_id', gu_id

            # log to mixpanel
            mix.track(
                uid, 'request change circle schedule', {
                    'time': dt.datetime.now(),
                    'appointment_type': appointment_type,
                    'have_pet': have_pet,
                    'master_gender': master_gender,
                    'isdirty': isdirty
                })

            # log to mongo
            mongo_logger.debug('request change circle schedule',
                               extra={
                                   'user_id': uid,
                                   'appointment_type': appointment_type,
                                   'have_pet': have_pet,
                                   'master_gender': master_gender,
                                   'isdirty': isdirty
                               })

            if len(available_schedules) > 0:  # 가능한 날짜가 있다면
                ret['response'] = {
                    'schedule': available_schedules,
                    'first_date': available_schedules.keys()[0]
                }
            else:
                add_err_message_to_response(ret, err_dict['err_not_available'])

            self.set_status(Response.RESULT_OK)
class UpdateScheduleHandler(tornado.web.RequestHandler):
    def get_amount_day_of_week_change(self, org_date, sel_date):
        if org_date.weekday() in BC.WEEKDAYS and sel_date.weekday() in BC.WEEKEND:
            return 10000
        elif org_date.weekday() in BC.WEEKEND and sel_date.weekday() in BC.WEEKDAYS:
            return -10000
        else:
            return 0

    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        ret = {}

        booking_id                  = self.get_argument('booking_id', '')

        uid                         = self.get_argument('uid', '')
        date                        = self.get_argument('date', dt.datetime.strftime(dt.datetime.now(), '%Y%m%d'))
        time                        = self.get_argument('time', '08:00')
        master_ids                  = self.get_argument('master_ids', [])
        apply_to_all_behind         = self.get_argument('apply_to_all_behind', 0)
        by_manager                  = self.get_argument('by_manager', 0)

        # convert parameters
        apply_to_all_behind         = int(apply_to_all_behind)
        selected_date_str           = date
        time_str                    = time
        selected_date               = dt.datetime.strptime(date, '%Y%m%d')
        master_ids                  = master_ids.split(',')
        by_manager                  = int(by_manager)

        # logging part
        mix = get_mixpanel()
        mongo_logger = get_mongo_logger()

        print 'update schedule'
        print selected_date_str, time_str, apply_to_all_behind
        print '*' * 100

        try:
            session = Session()

            booking_info = {}

            userdao     = UserDAO()
            masterdao   = MasterDAO()
            holder      = IntermediateValueHolder()

            try:
                row = session.query(Booking).filter(Booking.id == booking_id).one()
            except NoResultFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_no_record'])
                return

            except MultipleResultsFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_multiple_record'])
                return


            request_id              = row.request_id
            user_id                 = row.user_id
            user_name               = userdao.get_user_name(user_id)
            appointment_type        = row.appointment_type
            appointment_index       = row.appointment_index
            additional_task         = row.additional_task
            org_master_id           = row.master_id
            org_start_time          = row.start_time
            org_estimated_end_time  = row.estimated_end_time
            payment_status          = row.payment_status
            price_with_task         = row.price_with_task

            # 결제가 된 경우, 상황에 따라
            if payment_status == BC.BOOKING_PAID \
                                            and not userdao.is_b2b(user_id) \
                                            and row.source == 'hm':

                amount = self.get_amount_day_of_week_change(org_start_time, selected_date)
                if amount != 0:
                    ret_code, msg = cancel_payment(user_id, booking_id, price_with_task, '0', 'weeked_update_cancel')
                    if ret_code == True:
                        new_price = price_with_task + amount
                        ret_code, msg = request_payment(user_id, user_name, booking_id, new_price, appointment_type, status = 'PAID')
                        if ret_code == True:
                            row.payment_status = BC.BOOKING_PAID
                            row.tid = msg
                        else:
                            row.payment_status = BC.BOOKING_PAYMENT_FAILED

            duration = time_to_minutes(timedelta_to_time(org_estimated_end_time - org_start_time))

            if appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                appointment_type = BC.ONE_TIME

            if apply_to_all_behind == 0: # 단일 적용이라면
                appointment_type = BC.ONE_TIME

            count_of_iteration = appointment_type * 2 + 2 # 2 months

            # 편집 에러 기존 예약은 무조건 4개인데, 편집시 3개만 생성해서 에러가 발생
            # 꼼수로 4주 1회인 경우, iteration하나 늘림.
            if appointment_type == BC.ONE_TIME_A_MONTH:
                count_of_iteration += 1

            date_list = []
            for i in xrange(count_of_iteration):
                if appointment_type == 0:
                    appointment_type = 4

                date = selected_date + dt.timedelta(weeks = (4 / appointment_type) * i)
                date = dt.datetime.strftime(date, '%Y%m%d')
                date_list.append(date)


            booking_info['dates']            = date_list
            booking_info['time']             = time

            # 각 마스터별로 예약이 가능한지 메모리에서 다시 한번 확인.
            # 선택한 값을 메모리에 키로 저장하여 중복되는 예약 방지.
            # 선택 했으면 선택된 정보를 가지고 있어야 함
            master_num = len(master_ids)

            i = 0
            while i < master_num: # 랭킹이 높은 홈마스터별로 확인
                mid = master_ids[i]
                master_date_keys = []

                # 날짜별 키 생성
                for date in date_list:
                    key = '%s_%s' % (mid, date)
                    master_date_keys.append(key)

                # 저장할 키 생성
                booking_item_key = '%s_%s_%d' % (user_id, master_date_keys[0], appointment_type)

                if holder.store_keys(master_date_keys) and not masterdao.is_master_off_date(mid, selected_date.date()): # 메모리에 키가 하나도 없을 때, 즉 예약이 가능할 때
                    holder.store(booking_item_key, booking_info)

                    #master_date_keys = ','.join(master_date_keys)

                    if apply_to_all_behind == 0 or appointment_type == 0: # 1회성
                        booking_time       = dt.time(hour = int(time.split(':')[0]), minute = int(time.split(':')[1]))
                        start_time         = dt.datetime.combine(selected_date.date(), booking_time)

                        org_master_id   =  row.master_id
                        changed_master_id = mid

                        row.start_time          = start_time
                        row.estimated_end_time  = start_time + dt.timedelta(minutes = duration)
                        row.master_id           = mid
                        row.additional_task     = additional_task

                        if org_master_id != mid: # 기존 마스터님과 다르면
                            row.is_master_changed = 1

                        bid             = row.id
                        org_time        = convert_datetime_format2(org_start_time)
                        changed_time    = convert_datetime_format2(start_time)

                        amount = self.get_amount_day_of_week_change(org_start_time, selected_date)

                        row.price           += amount
                        row.price_with_task += amount
                        # 추가 결제 하거나, 부분 취소로 대체

                        mongo_logger.debug('update logs', extra = {'user_id' : user_id,
                                        'org_time' : org_time, 'changed_time' : changed_time,
                                        'booking_id' : bid, 'apply_to_all_behind' : apply_to_all_behind,
                                        'org_master_id' : org_master_id, 'changed_master_id' : changed_master_id,
                                        'by_manager' : by_manager})
                    else: # 전체 변경

                        print "idx", appointment_index
                        all_bookings = session.query(Booking) \
                                            .filter(Booking.request_id == request_id) \
                                            .filter(Booking.appointment_index >= appointment_index) \
                                            .filter(Booking.cleaning_status > BC.BOOKING_CANCELED) \
                                            .order_by(Booking.start_time) \
                                            .all()

                        former_bookings = session.query(Booking) \
                                            .filter(Booking.request_id == request_id) \
                                            .filter(Booking.appointment_index < appointment_index) \
                                            .order_by(Booking.start_time) \
                                            .all()

                        for former in former_bookings:
                            former.is_master_changed = 1

                        amount = self.get_amount_day_of_week_change(org_start_time, selected_date)

                        index = 0
                        for booking in all_bookings:
                            print 'booking udate loop'
                            if booking.cleaning_status != BC.BOOKING_COMPLETED and booking.cleaning_status != BC.BOOKING_STARTED:
                                booking.is_master_changed   = 0

                                booking_time       = dt.time(hour = int(time.split(':')[0]), minute = int(time.split(':')[1]))
                                start_time         = dt.datetime.combine(dt.datetime.strptime(date_list[index], '%Y%m%d'), booking_time)

                                org_start_time          = booking.start_time
                                org_estimated_end_time  = booking.estimated_end_time

                                duration = time_to_minutes(timedelta_to_time(org_estimated_end_time - org_start_time))

                                org_master_id   =  booking.master_id
                                changed_master_id = mid

                                booking.master_id           = mid
                                booking.org_start_time      = start_time
                                booking.start_time          = start_time
                                booking.estimated_end_time  = start_time + dt.timedelta(minutes = duration)
                                booking.price           += amount
                                booking.price_with_task += amount

                                bid             = booking.id
                                org_time        = convert_datetime_format2(org_start_time)
                                changed_time    = convert_datetime_format2(start_time)

                                '''
                                mongo_logger.debug('update logs', extra = {'user_id' : user_id,
                                                'org_time' : org_time, 'changed_time' : changed_time,
                                                'booking_id' : bid, 'apply_to_all_behind' : apply_to_all_behind,
                                                'org_master_id' : org_master_id, 'changed_master_id' : changed_master_id,
                                                'by_manager' : by_manager})
                                '''

                                index += 1
                            else:
                                continue


                    ret['response'] = Response.SUCCESS
                    self.set_status(Response.RESULT_OK)

                    session.commit()

                    holder.remove(booking_item_key)
                    for sk in master_date_keys:
                        print 'key : ', sk
                        holder.remove(sk)

                    user_name = userdao.get_user_name(user_id)

                    # manager alimtalk
                    #for manager_phone in MANAGERS_CALL.split(','):
                    #    send_alimtalk(manager_phone, 'noti_manager_modify_date', user_name, selected_date_str + time)

                    #master_pushkey = masterdao.get_master_pushkey(mid)
                    #send_booking_schedule_updated('android', [master_pushkey], booking_id, selected_date_str + ' ' + time_str)

                    # log to mixpanel
                    mix.track(user_id, 'update schedule', {'user_id' : user_id, 'date' : selected_date_str, 'time' : time, 'booking_id' : booking_id, 'apply_to_all_behind' : apply_to_all_behind})

                    # log to mongo
                    mongo_logger.debug('update schedule', extra = {'user_id' : user_id, 'date' : selected_date_str, 'time' : time, 'booking_id' : booking_id, 'apply_to_all_behind' : apply_to_all_behind})
                    return

                i += 1

            # log to mixpanel
            mix.track(user_id, 'cannot update schedule', {'time' : dt.datetime.now(), 'user_id' : user_id, 'date' : selected_date_str, 'time' : time, 'apply_to_all_behind' : apply_to_all_behind})

            # log to mongo
            mongo_logger.debug('cannot update schedule', extra = {'user_id' : user_id, 'date' : selected_date_str, 'time' : time, 'apply_to_all_behind' : apply_to_all_behind})

            # other users preempt homemasters, so no homemaster available
            self.set_status(Response.RESULT_OK)
            add_err_message_to_response(ret, err_dict['err_homemaster_occupied'])
            return
    def get_mybookings(self, session, user_id, mode):
        bookings = []

        now = dt.datetime.now()

        bookingdao = BookingDAO()

        try:
            if mode == 'upcoming':
                results = session.query(Booking) \
                                .group_by(Booking.request_id) \
                                .having(Booking.user_id == user_id) \
                                .order_by(func.min(Booking.start_time)) \
                                .all()

                for booking_row in results:
                    booking_result = session.query(Booking, Master, User) \
                                            .join(Master, Booking.master_id == Master.id) \
                                            .join(User, Booking.user_id == User.id) \
                                            .filter(Booking.request_id == booking_row.request_id) \
                                            .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED, Booking.cleaning_status == BC.BOOKING_CANCELED)) \
                                            .filter(func.date(Booking.start_time) >= now.date()) \
                                            .order_by(Booking.start_time) \
                                            .all()

                    for row in booking_result:
                        tooktime = time_to_minutes(
                            timedelta_to_time(row.Booking.estimated_end_time -
                                              row.Booking.start_time))

                        if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                            if row.Booking.is_dirty == 1:
                                tooktime -= 120

                        booking = {}
                        booking['id'] = row.Booking.id
                        booking['request_id'] = row.Booking.request_id
                        booking['index'] = row.Booking.appointment_index
                        booking['devicetype'] = row.User.devicetype
                        booking['datetime'] = convert_datetime_format(
                            row.Booking.start_time)
                        booking['tooktime'] = int(tooktime /
                                                  6)  # to make 2.5 to 25
                        booking[
                            'additional_task'] = row.Booking.additional_task
                        booking[
                            'master_name'] = row.Master.name if row.Master != None else ''
                        booking[
                            'master_img_url'] = row.Master.img_url if row.Master != None else ''
                        booking['status'] = row.Booking.cleaning_status
                        booking['payment_status'] = row.Booking.payment_status
                        booking[
                            'appointment_type'] = row.Booking.appointment_type
                        booking['cancel_reason'] = bookingdao.get_cancel_reason(
                            row.Booking.id
                        ) if row.Booking.cleaning_status == BC.BOOKING_CANCELED else ''

                        bookings.append(booking)

            elif mode == 'past':
                results = session.query(Booking) \
                                .group_by(Booking.request_id) \
                                .having(Booking.user_id == user_id) \
                                .order_by(func.min(Booking.start_time)) \
                                .all()

                print now.date()

                for booking_row in results:
                    booking_result = session.query(Booking, Master) \
                                            .join(Master, Booking.master_id == Master.id) \
                                            .filter(Booking.request_id == booking_row.request_id) \
                                            .filter(or_(Booking.cleaning_status == BC.BOOKING_COMPLETED, Booking.cleaning_status == BC.BOOKING_STARTED, Booking.cleaning_status == BC.BOOKING_CANCELED)) \
                                            .filter(func.date(Booking.start_time) <= now.date()) \
                                            .order_by(Booking.start_time) \
                                            .all()
                    for row in booking_result:
                        if row.Booking.cleaning_status == BC.BOOKING_COMPLETED:
                            end_time = row.Booking.end_time
                        else:
                            end_time = row.Booking.estimated_end_time

                        if row.Booking.working_start_time != None:
                            tooktime = time_to_minutes(
                                timedelta_to_time(
                                    end_time - row.Booking.working_start_time))
                        else:
                            tooktime = time_to_minutes(
                                timedelta_to_time(end_time -
                                                  row.Booking.start_time))

                        #if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                        #    if row.Booking.is_dirty == 1:
                        #        tooktime -= 120

                        booking = {}
                        booking['id'] = row.Booking.id
                        booking['request_id'] = row.Booking.request_id
                        booking['index'] = row.Booking.appointment_index
                        booking['datetime'] = convert_datetime_format(
                            row.Booking.start_time)
                        booking['tooktime'] = int(tooktime /
                                                  6)  # to make 2.5 to 25
                        booking['havereview'] = row.Booking.havereview
                        booking[
                            'additional_task'] = row.Booking.additional_task
                        booking[
                            'master_name'] = row.Master.name if row.Master != None else ''
                        booking[
                            'master_img_url'] = row.Master.img_url if row.Master != None else ''
                        booking['status'] = row.Booking.cleaning_status
                        booking['payment_status'] = row.Booking.payment_status
                        booking[
                            'appointment_type'] = row.Booking.appointment_type
                        booking['cancel_reason'] = bookingdao.get_cancel_reason(
                            row.Booking.id
                        ) if row.Booking.cleaning_status == BC.BOOKING_CANCELED else ''

                        bookings.append(booking)

        except Exception, e:
            print_err_detail(e)
            raise Exception(e)
            # time이 변경되었다면 무조건 scheduling
            if time_changed == '1':
                date = dt.datetime.strptime(date, '%Y%m%d')
                start_time_range_begin = int(start_time_range_begin)
                start_time_range_begin_min = int(start_time_range_begin_min)
                start_time_range_end = int(start_time_range_end)
                start_time_range_end_min = int(start_time_range_end_min)

                appointment_type = 0  # 여기서는 1회 청소로 한다. 편집이기 때문에
                start_time = row.start_time
                end_time = row.estimated_end_time
                have_pet = row.havepet
                master_gender = row.master_gender
                price_with_task = row.price_with_task

                org_taking_time_in_minutes = time_to_minutes(
                    timedelta_to_time(end_time - start_time))
                new_taking_time_in_minutes = org_taking_time_in_minutes + taking_time_in_minutes

                address, geohash5, geohash6 = userdao.get_user_address(uid)
                gu_id = addrdao.get_gu_id(address)
                dates = [int(dt.datetime.strftime(date, '%Y%m%d'))]

                schedule_by_date_list = masterdao.get_master_schedule_by_dates(
                    gu_id, have_pet, master_gender, dates)
                success, msg, store_key, search_keys, result = masterdao.find_master_by_score(schedule_by_date_list, \
                                                    gu_id, \
                                                    uid, \
                                                    appointment_type, \
                                                    dates, \
                                                    start_time_range_begin, \
                                                    start_time_range_begin_min, \
    def post(self):
        self.set_header("Content-Type", "application/json")

        ret = {}

        booking_id = self.get_argument('booking_id', '')
        additional_task = self.get_argument('additional_task', '')
        new_price = self.get_argument('new_price', 0)
        total_taking_time = self.get_argument('total_taking_time', '')
        laundry_apply_all = self.get_argument(
            'laundry_apply_all',
            0)  # -2 - 전체없앰 -1 - 하나 없앰, 0 - one time, 1 - all time

        # convert parameter
        new_price = int(new_price)
        additional_task = int(additional_task)
        total_taking_time = int(total_taking_time)
        total_taking_time_in_minutes = total_taking_time * 6
        laundry_apply_all = int(laundry_apply_all)

        print 'update additional task params'
        print booking_id
        print additional_task
        print new_price
        print total_taking_time
        print laundry_apply_all

        mix = get_mixpanel()
        mongo_logger = get_mongo_logger()

        try:
            print 'total_minutes :', total_taking_time_in_minutes
            if total_taking_time_in_minutes >= 720:
                self.set_status(Response.RESULT_OK)
                add_err_ko_message_to_response(
                    ret,
                    '클리닝 가능 시간을 초과하였습니다. (최대 12시간) 이전 화면으로 돌아가 추가사항을 2개이하로 줄여주세요.'
                )
                return

            session = Session()
            masterdao = MasterDAO()
            userdao = UserDAO()

            holder = IntermediateValueHolder()

            row = session.query(Booking).filter(Booking.id == booking_id).one()

            uid = row.user_id
            start_time = row.start_time
            end_time = row.estimated_end_time
            request_id = row.request_id
            appointment_index = row.appointment_index
            appointment_type = row.appointment_type
            payment_status = row.payment_status
            price_with_task = row.price_with_task

            isdirty = row.is_dirty
            if isdirty == 1:
                total_taking_time_in_minutes += 120

            org_taking_time_in_minutes = time_to_minutes(
                timedelta_to_time(end_time - start_time))

            is_event = session.query(UserFreeEvent) \
                            .filter(UserFreeEvent.booking_request_id == request_id) \
                            .first()

            is_event = True if is_event != None else False

            user_name = userdao.get_user_name(uid)

            # 추가 업무로 인해 소요된 시간이 더 크다면 앞 뒤 일정을 고려.
            # 고려해서 이동이 가능하다면 추가 업무 할당함.
            if total_taking_time_in_minutes > org_taking_time_in_minutes:
                print '2'
                master_id, time = masterdao.get_masterid_and_starttime_from_booking(
                    booking_id)
                search_key = '%s_%d' % (master_id, time)
                new_estimated_end_time = masterdao.is_schedule_extend_available(
                    booking_id, total_taking_time_in_minutes)

                if new_estimated_end_time != None and holder.store(
                        search_key, 1):  # 변경이 가능함.
                    if payment_status == BC.BOOKING_PAID:  # 미리 지불한 경우는 취소 하고 다시 결제함
                        # 전거래 취소 및 재결제
                        if not (is_event and appointment_index == 1):
                            print 'in this case'
                            cancel_ret_code, msg = cancel_payment(
                                uid, booking_id, price_with_task, partial='0')
                            if cancel_ret_code:

                                pay_ret_code, pay_msg = request_payment(
                                    uid,
                                    user_name,
                                    booking_id,
                                    new_price,
                                    appointment_type,
                                    status='UPDATED')
                                if pay_ret_code:
                                    row.tid = pay_msg
                                    row.payment_status = BC.BOOKING_PAID
                                else:
                                    row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                    session.commit()
                                    session.close()
                                    self.set_status(Response.RESULT_OK)
                                    add_err_ko_message_to_response(
                                        ret, pay_msg)
                                    return
                        else:  # 정기 1회 이벤트 일 때
                            print 'hahaha'
                            charge_amount = new_price - row.price
                            print charge_amount

                            if row.price_with_task != row.price:  # 다르면
                                charge_amount = new_price - row.price_with_task

                            pay_ret_code, pay_msg = request_payment(
                                uid,
                                user_name,
                                booking_id,
                                charge_amount,
                                appointment_type,
                                status='UPDATED')
                            if pay_ret_code:
                                row.tid = pay_msg
                                row.payment_status = BC.BOOKING_PAID
                            else:
                                row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                session.commit()
                                session.close()
                                self.set_status(Response.RESULT_OK)
                                add_err_ko_message_to_response(ret, pay_msg)
                                return

                    row.estimated_end_time = new_estimated_end_time
                    row.additional_task = additional_task
                    row.price_with_task = new_price
                    row.laundry_apply_all = laundry_apply_all

                    session.commit()
                    holder.remove(search_key)

                else:
                    print '3'
                    session.close()
                    self.set_status(Response.RESULT_OK)
                    add_err_message_to_response(
                        ret, err_dict['err_hm_have_next_schedule'])

                    # 메모리에서 삭제
                    holder.remove(search_key)
                    return

            else:  # 같거나 작은 경우는 바로 변경
                print '4'
                if payment_status == BC.BOOKING_PAID:  # 미리 지불한 경우는 취소 하고 다시 결제함
                    # 전거래 취소 및 재결제
                    if not (is_event and appointment_index == 1):
                        cancel_ret_code, msg = cancel_payment(uid,
                                                              booking_id,
                                                              price_with_task,
                                                              partial='0')
                        if cancel_ret_code:
                            user_name = userdao.get_user_name(uid)
                            pay_ret_code, pay_msg = request_payment(
                                uid,
                                user_name,
                                booking_id,
                                new_price,
                                appointment_type,
                                status='UPDATED')
                            if pay_ret_code:
                                row.tid = pay_msg
                                row.payment_status = BC.BOOKING_PAID
                            else:
                                row.payment_status = BC.BOOKING_PAYMENT_FAILED
                                session.commit()
                                session.close()
                                self.set_status(Response.RESULT_OK)
                                add_err_ko_message_to_response(ret, pay_msg)
                                return
                    else:
                        if row.price_with_task != row.price:  # 다르면
                            charge_amount = row.price_with_task - new_price
                            cancel_payment(uid,
                                           booking_id,
                                           charge_amount,
                                           partial='0')

                row.additional_task = additional_task
                row.estimated_end_time = end_time + dt.timedelta(
                    minutes=total_taking_time_in_minutes -
                    org_taking_time_in_minutes)
                row.price_with_task = new_price
                row.laundry_apply_all = laundry_apply_all

            # 빨래의 경우는 시간 변경이 없으므로 마지막에 바로 적용
            # about laundry

            print '5'
            all_upcoming_bookings = session.query(Booking) \
                    .filter(Booking.request_id == request_id) \
                    .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                    .filter(Booking.appointment_index >= appointment_index) \
                    .all()

            if laundry_apply_all == 1:  # 전체 선택
                for booking in all_upcoming_bookings:
                    bits = "{0:07b}".format(booking.additional_task)
                    if bits[4] == '0':  # 빨래가 세팅되어 있다면
                        booking.additional_task += 4  # 빨래
                    booking.laundry_apply_all = laundry_apply_all

            elif laundry_apply_all == -2:  # 선택 해제
                for booking in all_upcoming_bookings:
                    bits = "{0:07b}".format(booking.additional_task)
                    if bits[4] == '1':  # 빨래가 세팅되어 있다면
                        booking.additional_task -= 4  # 빨래 제거
                    booking.laundry_apply_all = laundry_apply_all

            print '6'

            session.commit()

            # alim talk
            user_name = userdao.get_user_name(uid)
            additional_task_str = additional_task_string(additional_task)

            #for manager_phone in MANAGERS_CALL.split(','):
            #    send_alimtalk(manager_phone, 'noti_manager_modify_task', user_name, additional_task_str)

            # log to mixpanel
            mix.track(
                uid, 'update additional task', {
                    'time': dt.datetime.now(),
                    'booking_id': booking_id,
                    'additional_task': additional_task,
                    'new_price': new_price,
                    'total_taking_time': total_taking_time,
                    'laundry_apply_all': laundry_apply_all
                })

            # log to mongo
            mongo_logger.debug('update additional task',
                               extra={
                                   'user_id': uid,
                                   'booking_id': booking_id,
                                   'additional_task': additional_task,
                                   'new_price': new_price,
                                   'total_taking_time': total_taking_time,
                                   'laundry_apply_all': laundry_apply_all
                               })

            ret['response'] = Response.SUCCESS
            self.set_status(Response.RESULT_OK)

        except NoResultFound, e:
            print_err_detail(e)
            session.close()
            self.set_status(Response.RESULT_OK)
            add_err_message_to_response(ret, err_dict['err_no_record'])
            return
                            cur_date,
                            master['free_to']):  # add available time list
                    #while cur_time + dt.timedelta(minutes = taking_time) <= master['free_to']: # add available time list
                    master['available_times'].append(
                        self.time_to_str(cur_time))  # for json serialization
                    cur_time += dt.timedelta(minutes=30)

                    #if master_id == 'e1d543b5-a0d5-4ed0-b5db-24cf63db4453' and dt.datetime.strftime(cur_date, '%Y%m%d') == '20160603':
                    #print cur_date, cur_time
            else:
                for i, slot in enumerate(master['occupied_times']):
                    time1 = slot[1]
                    time2 = master['occupied_times'][i + 1][0] if i + 1 < len(
                        master['occupied_times']) else master['free_to']

                    if time2 > time1 and time_to_minutes(
                            timedelta_to_time(time2 - time1)) > taking_time:
                        geohash1 = slot[2]
                        geohash2 = master['occupied_times'][
                            i + 1][2] if i + 1 < len(
                                master['occupied_times']) else None

                        moving_time1 = get_moving_time(geohash1, geohash)
                        moving_time2 = get_moving_time(geohash2, geohash)

                        # 앞 뒤 2시간 이상이 걸리거나, 합계로 150분 초과로 걸리는 것 상황은 일을 배정하지 않는다.
                        #if moving_time1 >= 120 or moving_time2 >= 120 or moving_time1 + moving_time2 > 150:
                        #    continue

                        cur_time = time1 + dt.timedelta(minutes=moving_time1)

                        while dt.datetime.combine(
예제 #9
0
    def post(self):
        self.set_header("Content-Type", "application/json")

        booking_id = self.get_argument('booking_id', '')
        new_master_id = self.get_argument('new_master_id', '')

        ret = {}

        try:
            session = Session()

            userdao = UserDAO()
            addrdao = AddressDAO()
            masterdao = MasterDAO()

            holder = IntermediateValueHolder()

            row = session.query(Booking).filter(Booking.id == booking_id).one()

            uid                     = row.user_id 
            master_id_to_change     = row.master_id
            org_start_time          = row.start_time
            org_end_time            = row.estimated_end_time
            appointment_type        = 0 # 여기서는 1회 청소로 한다. 편집이기 때문에
            have_pet                = row.havepet
            master_gender           = row.master_gender
            addr_idx                = row.addr_idx

            taking_time_in_minutes = time_to_minutes(timedelta_to_time(org_end_time - org_start_time))

            address, geohash5, geohash6 = userdao.get_user_address_by_index(uid, addr_idx)
            gu_id = addrdao.get_gu_id(address)
            dates = [int(dt.datetime.strftime(org_start_time, '%Y%m%d'))]

            time_range_begin     = org_start_time.hour 
            time_range_begin_min = org_start_time.minute
            time_range_end       = org_start_time.hour 
            time_range_end_min   = org_start_time.minute

            print gu_id, dates
            print time_range_begin
            print time_range_begin_min
            print time_range_end
            print time_range_end_min
            print taking_time_in_minutes

            schedule_by_date_list = masterdao.get_master_schedule_by_dates(gu_id, have_pet, master_gender, dates, new_master_id)

            print schedule_by_date_list

            success, msg, store_key, search_keys, result = masterdao.find_master_by_score(schedule_by_date_list, \
                                                gu_id, \
                                                uid, \
                                                appointment_type, \
                                                dates, \
                                                time_range_begin, \
                                                time_range_begin_min, \
                                                time_range_end, \
                                                time_range_end_min, \
                                                taking_time_in_minutes, \
                                                geohash6)

            if success != 'SUCCESS':
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_no_hm_at_that_time'])
                #self.write(json.dumps(ret)) 

                print booking_id, ' WAS NOT ... successfully updated to master_id : ', new_master_id
                return     
            else:
                row.master_id = result[0]['mid']
                if master_id_to_change != row.master_id:
                    row.is_master_changed = 1

                session.commit()

                holder.remove(store_key)
                for sk in search_keys:
                    holder.remove(sk)

                ret['response'] = Response.SUCCESS
                self.set_status(Response.RESULT_OK)

                print booking_id, ' was successfully updated to master_id : ', new_master_id
                
        except Exception, e:
            session.rollback()

            print_err_detail(e)
            self.set_status(Response.RESULT_SERVERERROR)
            add_err_message_to_response(ret, err_dict['err_mysql'])
class MyBookingsDetailHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header("Content-Type", "application/json")

        booking_id  = self.get_argument('booking_id', '')

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        try:
            booking_detail = {}
            session = Session()

            print booking_id

            try:
                row = session.query(Booking, Master, UserAddress, Promotion, UserCoupon) \
                            .join(Master, Booking.master_id == Master.id) \
                            .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                            .outerjoin(Promotion, Booking.id == Promotion.booking_id) \
                            .outerjoin(UserCoupon, Booking.id == UserCoupon.booking_id) \
                            .filter(Booking.id == booking_id) \
                            .one()

            except NoResultFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_no_record'])
                return

            except MultipleResultsFound, e:
                session.close()
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret, err_dict['err_multiple_record'])
                return

            tooktime = time_to_minutes(timedelta_to_time(row.Booking.estimated_end_time - row.Booking.start_time))

            if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                if row.Booking.is_dirty == 1:
                    tooktime -= 120

            masterdao = MasterDAO()
            master_name, master_img_url, master_rating = masterdao.get_master_name_img_and_average_rating(row.Master.id)

            booking_detail['id']                = row.Booking.id
            booking_detail['index']             = row.Booking.appointment_index
            booking_detail['havereview']        = row.Booking.havereview
            booking_detail['master_name']       = master_name
            booking_detail['master_img_url']    = master_img_url
            booking_detail['master_img_url']    = master_img_url
            booking_detail['master_rating']     = str(float(master_rating))
            booking_detail['size']              = row.UserAddress.size
            booking_detail['kind']              = row.UserAddress.kind
            booking_detail['datetime']          = convert_datetime_format(row.Booking.start_time)
            booking_detail['tooktime']          = int(tooktime / 6) # to make 2.5 to 25
            booking_detail['address_idx']       = row.Booking.addr_idx
            booking_detail['period']            = row.Booking.appointment_type
            booking_detail['additional_task']   = row.Booking.additional_task
            booking_detail['price']             = row.Booking.price
            booking_detail['actual_price']      = row.Booking.price_with_task
            booking_detail['card_idx']          = row.Booking.card_idx
            booking_detail['message']           = row.Booking.message
            booking_detail['cleaning_status']   = row.Booking.cleaning_status
            booking_detail['payment_status']    = row.Booking.payment_status

            booking_detail['promotion_applied'] = 1 if row.Promotion != None else 0
            booking_detail['coupon_applied']    = 1 if row.UserCoupon != None else 0

            discount_price = 0

            if row.UserCoupon != None:
                discount_price = row.UserCoupon.discount_price
                price = row.Booking.price_with_task

                if discount_price <= 100:
                    amount_discount_percent = 100 - discount_price
                    before_price = int(price * 100 / float(amount_discount_percent))
                    print 'before_price : ', before_price
                    discount_price = int(before_price * float(discount_price) / 100)
                    print 'discount_price : ', discount_price

            booking_detail['coupon_discount_price']  = discount_price

            #booking_detail['laundry_apply_all'] = row.Booking.laundry_apply_all


            start_time = row.Booking.start_time
            request_id = row.Booking.request_id

            next_start_time = session.query(Booking.start_time) \
                                    .filter(Booking.request_id == request_id) \
                                    .filter(Booking.start_time > start_time) \
                                    .order_by(Booking.start_time) \
                                    .first()


            if next_start_time != None:
                booking_detail['next_datetime']     = dt.datetime.strftime(next_start_time[0], '%Y%m%d %H%M')
            else:
                booking_detail['next_datetime']     = ''

            ret['response'] = booking_detail
            self.set_status(Response.RESULT_OK)

            user_id = row.Booking.user_id

            mix.track(user_id, 'got booking detail', {'time' : dt.datetime.now(), 'id' : row.Booking.id})
            mongo_logger.debug('got booking detail', extra = {'user_id' : user_id})

            print booking_id, 'successfully retrieved...by', user_id
    def post(self):
            self.set_header("Content-Type", "application/json")

            ret = {}

            store_key               = self.get_argument('store_key', '')
            uid                     = self.get_argument('uid', '')
            mid                     = self.get_argument('mid', '')
            appointment_type        = self.get_argument('appointment_type', BC.ONE_TIME)
            additional_task         = self.get_argument('additional_task', 0)
            discounted_price        = self.get_argument('discounted_price', 0)
            price                   = self.get_argument('price', 0)
            price_with_task         = self.get_argument('price_with_task', 0)
            promotion_code          = self.get_argument('promotion_code', '')
            have_pet                = self.get_argument('have_pet', 0)
            search_keys             = self.get_argument('search_keys', '')
            master_gender           = self.get_argument('master_gender', 0)
            isdirty                 = self.get_argument('isdirty', 0)
            first_added_time        = self.get_argument('first_added_time', 0)
            additional_time         = self.get_argument('additional_time', 10)
            laundry_apply_all       = self.get_argument('laundry_apply_all', 0) # -1 - 없앰, 0 - one time, 1 - all time

            # convert datetime
            appointment_type        = int(appointment_type)
            additional_task         = int(additional_task)
            price                   = int(price)
            price_with_task         = int(price_with_task)
            discounted_price        = int(discounted_price)
            have_pet                = int(have_pet)
            master_gender           = int(master_gender)
            isdirty                 = int(isdirty)
            laundry_apply_all       = int(laundry_apply_all)


            first_added_time        = int(first_added_time)
            additional_time         = int(additional_time)
            first_added_time_in_minutes   = first_added_time * 6
            additional_time_in_minutes    = additional_time * 6 

            print first_added_time, additional_time

            search_keys = search_keys.split(',')


            havetools = 1
            if additional_task >= 64:
                havetools = 0

            mongo_logger = get_mongo_logger()

            mongo_logger.debug('%s request booking' % uid, extra = {    'uid' : uid, 'mid' : mid,
                                                                        'appointment_type' : appointment_type, 
                                                                        'have_pet' : have_pet, 'master_gender' : master_gender,
                                                                        'isdirty' : isdirty})

            mix = get_mixpanel()

            try:
                session = Session()
                userdao = UserDAO()
                promotiondao = PromotionDAO()

                holder = IntermediateValueHolder()

                card_idx = 0
                addr_idx = 0

                # get card and address idx
                addr_idx = userdao.get_user_default_address_index(uid)
                card_idx = userdao.get_user_default_card_index(uid)

                # hasids to generate unique booking id
                now = dt.datetime.strftime(dt.datetime.now(), '%Y%m%d%H%M%S')
                hashids = Hashids(min_length = 16, salt = now + uid)
                print 'salt : ', now + uid

                # request id to group each individual bookings
                request_id = str(uuid.uuid4())

                obj = holder.retrieve(store_key)
                if obj == None:
                    session.close()
                    self.set_status(Response.RESULT_OK)
                    add_err_message_to_response(ret, err_dict['err_booking_timeout'])
                    mix.track(uid, 'request timeout', {'time' : dt.datetime.now()})
                    mongo_logger.error('%s got timed out' % uid)
                    self.write(json.dumps(ret)) 
                    return  

                i = 1
                booking_ids = []
                start_time_list = []

                obj = sorted(obj, key = lambda x: x['date'])

                for item in obj:
                    print item['date']
                    booking_id = hashids.encode(int(item['date'] + time_to_str(item['start_time'])))
                    master_id = item['mid']

                    dow                = dt.datetime.strptime(item['date'], '%Y%m%d').date().weekday()
                    start_time         = dt.datetime.combine(dt.datetime.strptime(item['date'], '%Y%m%d'), item['start_time'])
                    estimated_end_time = dt.datetime.combine(dt.datetime.strptime(item['date'], '%Y%m%d'), item['end_time'])

                    cleaning_duration = time_to_minutes(timedelta_to_time(estimated_end_time - dt.timedelta(minutes=additional_time_in_minutes + first_added_time_in_minutes) - start_time))

                    actual_price = 0
                    if i == 1: # 1 번째 클리닝
                        actual_price = price_with_task - discounted_price # 할인은 1회만 적용됨

                    else: # 나머지
                        actual_price = price
                        if havetools == 1:
                            additional_task = 0
                        else: 
                            additional_task = 64
                            #actual_price += BC.VACCUM_CHARGE

                        if laundry_apply_all == 1:
                            additional_task += 4 # 빨래

                        isdirty = 0 # 첫째 이후에는 is dirty는 0
                        estimated_end_time = estimated_end_time - dt.timedelta(minutes=additional_time_in_minutes + first_added_time_in_minutes)


                    booking = Booking(id = booking_id, 
                                      request_id = request_id, 
                                      user_id = uid, 
                                      master_id = mid, 
                                      appointment_type = appointment_type, 
                                      appointment_index = i,
                                      dow = dow,
                                      booking_time = dt.datetime.now(),
                                      org_start_time = start_time,
                                      start_time = start_time,
                                      estimated_end_time = estimated_end_time,
                                      end_time = estimated_end_time, # update after homemaster finish their job
                                      cleaning_duration = cleaning_duration,
                                      additional_task = additional_task, 
                                      price = price,
                                      price_with_task = actual_price,
                                      charging_price = 0,
                                      card_idx = card_idx, 
                                      addr_idx = addr_idx, 
                                      havetools = havetools, 
                                      havepet = have_pet,
                                      laundry_apply_all = laundry_apply_all,
                                      is_dirty = isdirty,
                                      master_gender = master_gender,
                                      status = BC.BOOKING_UPCOMMING, 
                                      cleaning_status = BC.BOOKING_UPCOMMING,
                                      payment_status = BC.BOOKING_UNPAID_YET)
                    i += 1

                    session.add(booking) 
                    booking_ids.append(booking_id)
                    start_time_list.append(start_time)

                    #print 'booking_id', booking_id, 'was added..'

                # charge for first appointment date
                user_name = userdao.get_user_name(uid)
                if price_with_task - discounted_price <= 0:
                    ret_code = True
                    msg = ''
                else:
                    ret_code, msg = request_payment(uid, user_name, booking_ids[0], price_with_task - discounted_price, appointment_type)

                # 결제 정보 출력
                print user_name, ret_code, msg

                if ret_code:
                    session.commit()

                    # remove store_key and related_keys
                    holder.remove(store_key)
                    for sk in search_keys:
                        holder.remove(sk)

                    # promotion code 와 연결
                    if promotion_code != '':
                        promotiondao.set_promotion_code_status(promotion_code, 1, booking_ids[0], price_with_task)

                    # change status to paid
                    try:
                        first_booking = session.query(Booking).filter(Booking.id == booking_ids[0]).one()
                    except NoResultFound, e:
                        session.close()
                        self.set_status(Response.RESULT_OK)
                        mongo_logger.debug('no first booking record', extra = {    'uid' : uid, 'mid' : mid,'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender, 'isdirty' : isdirty})
                        add_err_message_to_response(ret, err_dict['err_no_record'])
                        return                

                    except MultipleResultsFound, e:
                        session.close()
                        self.set_status(Response.RESULT_OK)
                        mongo_logger.debug('multiple first booking record', extra = {    'uid' : uid, 'mid' : mid, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender, 'isdirty' : isdirty})
                        add_err_message_to_response(ret, err_dict['err_multiple_record'])
                        return  
예제 #12
0
    def get_mybookings(self, session, user_id, mode):
        bookings = []

        try:
            if mode == 'upcoming':
                results = session.query(Booking) \
                                .group_by(Booking.request_id) \
                                .having(Booking.user_id == user_id) \
                                .order_by(func.min(Booking.start_time)) \
                                .all()

                for booking_row in results:
                    booking_result = session.query(Booking, Master, User) \
                                            .join(Master, Booking.master_id == Master.id) \
                                            .join(User, Booking.user_id == User.id) \
                                            .filter(Booking.request_id == booking_row.request_id) \
                                            .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED)) \
                                            .order_by(Booking.start_time) \
                                            .all()

                    for row in booking_result:
                        try:
                            tooktime = time_to_minutes(timedelta_to_time(row.Booking.estimated_end_time - row.Booking.start_time))
                        except Exception, e:
                            print_err_detail(e)
                            tooktime = 180

                        if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                            if row.Booking.is_dirty == 1:
                                tooktime -= 120

                        booking = {}
                        booking['id']               = row.Booking.id
                        booking['request_id']       = row.Booking.request_id
                        booking['index']            = row.Booking.appointment_index
                        booking['devicetype']       = row.User.devicetype
                        booking['datetime']         = convert_datetime_format(row.Booking.start_time)
                        booking['tooktime']         = int(tooktime / 6) # to make 2.5 to 25
                        booking['additional_task']  = row.Booking.additional_task
                        booking['master_name']      = row.Master.name if row.Master != None else ''
                        booking['master_img_url']   = row.Master.img_url if row.Master != None else ''

                        bookings.append(booking)

            elif mode == 'cancel':
                results = session.query(Booking) \
                                .group_by(Booking.request_id) \
                                .having(Booking.user_id == user_id) \
                                .order_by(func.min(Booking.start_time)) \
                                .all()

                for booking_row in results:
                    booking_result = session.query(Booking, Master, User) \
                                            .join(Master, Booking.master_id == Master.id) \
                                            .join(User, Booking.user_id == User.id) \
                                            .filter(Booking.request_id == booking_row.request_id) \
                                            .filter(Booking.cleaning_status == BC.BOOKING_CANCELED) \
                                            .order_by(Booking.start_time) \
                                            .all()
                    for row in booking_result:
                        try:
                            tooktime = time_to_minutes(timedelta_to_time(row.Booking.estimated_end_time - row.Booking.start_time))
                        except Exception, e:
                            print_err_detail(e)
                            tooktime = 180

                        if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                            if row.Booking.is_dirty == 1:
                                tooktime -= 120

                        booking = {}
                        booking['id']               = row.Booking.id
                        booking['request_id']       = row.Booking.request_id
                        booking['index']            = row.Booking.appointment_index
                        booking['devicetype']       = row.User.devicetype
                        booking['datetime']         = convert_datetime_format(row.Booking.start_time)
                        booking['tooktime']         = int(tooktime / 6) # to make 2.5 to 25
                        booking['additional_task']  = row.Booking.additional_task
                        booking['master_name']      = row.Master.name if row.Master != None else ''
                        booking['master_img_url']   = row.Master.img_url if row.Master != None else ''

                        bookings.append(booking)
예제 #13
0
                results = session.query(Booking) \
                                .group_by(Booking.request_id) \
                                .having(Booking.user_id == user_id) \
                                .order_by(func.min(Booking.start_time)) \
                                .all()

                for booking_row in results:
                    booking_result = session.query(Booking, Master) \
                                            .join(Master, Booking.master_id == Master.id) \
                                            .filter(Booking.request_id == booking_row.request_id) \
                                            .filter(Booking.cleaning_status == BC.BOOKING_COMPLETED) \
                                            .order_by(Booking.start_time) \
                                            .all()
                    for row in booking_result:
                        try:
                            tooktime = time_to_minutes(timedelta_to_time(row.Booking.estimated_end_time - row.Booking.start_time))
                        except Exception, e:
                            print_err_detail(e)
                            tooktime = 180

                        #if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                        #    if row.Booking.is_dirty == 1:
                        #        tooktime -= 120

                        # 클리닝 및 홈마스터 평가를 클리닝 후 2일 이내로 제한 두기
                        havereview = row.Booking.havereview
                        if row.Booking.havereview == 0:
                            diff = now - row.Booking.end_time
                            havereview = 0 if diff.days < 2 else 1

                        booking = {}
예제 #14
0
    def post(self):
        self.set_header("Content-Type", "application/json")

        master_id = self.get_argument('master_id', '')

        ret = {}

        # 해당 마스터의 상태를 deactivate 시킨다.
        # 남아있는 일정이 있다면 모든 일정을 다른 마스터에게 양도 한다.

        try:
            session = Session()

            userdao = UserDAO()
            addrdao = AddressDAO()
            masterdao = MasterDAO()

            holder = IntermediateValueHolder()

            # deactivate master
            row = session.query(Master).filter(Master.id == master_id).one()
            row.active = 0
            session.commit()

            # automatically assign that master's remain jobs to other masters
            masterdao = MasterDAO()
            request_ids = masterdao.get_distinct_req_ids(master_id)

            matched_booking_groups = []
            unmatched_booking_groups = []

            for req_id in request_ids:
                reqs = session.query(Booking, User, UserAddress) \
                    .join(User, User.id == Booking.user_id) \
                    .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                    .filter(Booking.request_id == req_id).filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                    .order_by(Booking.start_time) \
                    .all()

                key = userdao.get_user_salt_by_id(reqs.User.id)[:16]
                crypto = aes.MyCrypto(key)

                dates = []
                datetimes = []
                max_taking_time_in_minutes = 0
                for item in reqs:
                    appointment_type = item.Booking.appointment_type
                    address = crypto.decodeAES(item.UserAddress.address)
                    geohash5 = item.UserAddress.geohash5
                    geohash6 = item.UserAddress.geohash6
                    start_time = item.Booking.start_time
                    end_time = item.Booking.estimated_end_time

                    # 최대 시간 기준으로 할당을 잡음
                    taking_time_in_minutes = time_to_minutes(
                        timedelta_to_time(end_time - start_time))
                    if taking_time_in_minutes > max_taking_time_in_minutes:
                        max_taking_time_in_minutes = taking_time_in_minutes

                    gu_id = addrdao.get_gu_id(address)
                    dates.append(
                        int(dt.datetime.strftime(start_time, '%Y%m%d')))

                    datetimes.append(start_time)

                uid = item.Booking.user_id
                time_range_begin = datetimes[0].hour
                time_range_begin_min = datetimes[0].minute
                time_range_end = datetimes[0].hour
                time_range_end_min = datetimes[0].minute
                have_pet = item.Booking.havepet
                master_gedner = item.Booking.master_gender

                schedule_by_date_list = masterdao.get_master_schedule_by_dates(
                    gu_id, have_pet, master_gender, dates)
                success, msg, store_key, search_keys, result = masterdao.find_master_by_score(schedule_by_date_list, \
                                                    gu_id, \
                                                    uid, \
                                                    appointment_type, \
                                                    dates, \
                                                    time_range_begin, \
                                                    time_range_begin_min, \
                                                    time_range_end, \
                                                    time_range_end_min, \
                                                    max_taking_time_in_minutes, \
                                                    geohash6)

                if success == 'SUCCESS':
                    matched_booking_groups.append(req_id)

                    matched_list = session.query(Booking) \
                                        .filter(Booking.request_id == req_id) \
                                        .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                                        .all()

                    for match in matched_list:
                        match.master_id = result[0]['mid']

                    session.commit()

                    holder.remove(store_key)
                    for sk in search_keys:
                        holder.remove(sk)

                else:
                    unmatched_booking_groups.append(req_id)

                    unmatched_list = session.query(Booking) \
                                        .filter(Booking.request_id == req_id) \
                                        .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                                        .all()

                    for unmatch in unmatched_list:
                        print unmatch
                        unmatch.master_id = None

                    session.commit()

            ret['response'] = {
                'matched_group': matched_booking_groups,
                'unmatched_group': unmatched_booking_groups
            }
            self.set_status(Response.RESULT_OK)

        except NoResultFound, e:
            session.rollback()

            print_err_detail(e)
            self.set_status(Response.RESULT_SERVERERROR)
            add_err_message_to_response(ret, err_dict['err_no_record'])