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

        master_id = self.get_argument('master_id', '')
        off_date = self.get_argument('off_date', '')  # 20160603

        master_date_key = '{0}_{1}'.format(master_id, off_date)

        off_date = dt.datetime.strptime(off_date, '%Y%m%d')

        ret = {}

        try:
            session = Session()
            masterdao = MasterDAO()

            # add request logs
            # type : 1 - request, 0 - cancel
            day_off_request = MasterDayoffRequest(
                master_id=master_id,
                date=off_date,
                type=0,
                request_time=dt.datetime.now())
            session.add(day_off_request)

            # master schedules by date active -> 0
            row = session.query(MasterScheduleByDate) \
                    .filter(MasterScheduleByDate.master_id == master_id) \
                    .filter(MasterScheduleByDate.date == off_date) \
                    .one()

            row.active = 1

            # commit
            session.commit()

            master_name = masterdao.get_master_name(master_id)
            send_jandi('HOMEMASTER_REST', "휴무 신청 취소",
                       master_name + ' 홈마스터님 휴무 신청 취소',
                       '휴무 취소 날짜 : {}'.format(off_date))

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

            print 'master_id', master_id, 'cancel dayoff request', off_date

        except NoResultFound, e:
            self.set_status(Response.RESULT_OK)
            add_err_ko_message_to_response(ret, '휴무 신청 취소 가능 날짜가 아닙니다.')
            return
    def update_new_master_schedule_with_active(self, master_id,
                                               non_active_dates):
        try:
            session = Session()

            masterdao = MasterDAO()
            max_date = masterdao.get_master_schedule_max_date()
            free_times_by_date = masterdao.get_available_time_by_date(
                master_id)

            print free_times_by_date

            current_date = dt.datetime.now().date() + dt.timedelta(days=1)

            print current_date, max_date

            while current_date <= max_date:
                free_times = free_times_by_date[current_date.weekday(
                )] if current_date.weekday() in free_times_by_date else None

                if free_times != None:
                    free_from = free_times[0]
                    free_to = free_times[1]

                    active = 1
                    if current_date in non_active_dates:
                        active = 0

                    schedule_by_date = MasterScheduleByDate(
                        master_id=master_id,
                        date=current_date,
                        free_from=free_from,
                        free_to=free_to,
                        active=active)
                    session.add(schedule_by_date)

                current_date += dt.timedelta(days=1)

            session.commit()
            print 'build schedule successfully performed its task for master', master_id, 'in', dt.datetime.now(
            )

        except Exception, e:
            session.rollback()
            print_err_detail(e)
    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
    def initial_build_schedule(self):
        try:
            # 모든 홈마스터에 대해, 오늘 이후 20주 데이터 빌드 (140 days)
            NUM_DAYS = 140

            session = Session()

            masterdao = MasterDAO()
            master_ids = masterdao.get_all_master_ids()

            for mid in master_ids:
                today = dt.datetime.now()

                free_times_by_date = masterdao.get_available_time_by_date(mid)

                for i in xrange(NUM_DAYS):
                    date = today + dt.timedelta(days=(i + 1))
                    free_times = free_times_by_date[date.weekday(
                    )] if date.weekday() in free_times_by_date else None

                    if free_times != None:
                        free_from = free_times[0]
                        free_to = free_times[1]

                        schedule_by_date = MasterScheduleByDate(
                            master_id=mid,
                            date=date.date(),
                            free_from=free_from,
                            free_to=free_to)
                        session.add(schedule_by_date)

            session.commit()

        except Exception, e:
            session.rollback()
            print_err_detail(e)
    def build_schedule_weekly(self):
        try:
            DAYS_IN_A_WEEK = 7

            session = Session()

            masterdao = MasterDAO()
            max_date = masterdao.get_master_schedule_max_date()
            master_ids = masterdao.get_all_master_ids()

            for mid in master_ids:
                free_times_by_date = masterdao.get_available_time_by_date(mid)

                for i in xrange(DAYS_IN_A_WEEK):
                    date = max_date + dt.timedelta(days=i + 1)
                    free_times = free_times_by_date[date.weekday(
                    )] if date.weekday() in free_times_by_date else None

                    if free_times != None:
                        free_from = free_times[0]
                        free_to = free_times[1]

                        schedule_by_date = MasterScheduleByDate(
                            master_id=mid,
                            date=date,
                            free_from=free_from,
                            free_to=free_to)
                        session.add(schedule_by_date)

            session.commit()
            print 'build schedule weekly successfully performed its task in', dt.datetime.now(
            )

        except Exception, e:
            session.rollback()
            print_err_detail(e)
    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        master_ids = self.get_argument('master_ids', '')
        ret = {}

        try:
            master_name_dict = {}

            masterdao = MasterDAO()
            master_ids = master_ids.split(',')
            for mid in master_ids:
                master_name = masterdao.get_master_name(mid)
                master_name_dict[mid] = master_name

            ret['response'] = master_name_dict

            self.set_status(Response.RESULT_OK)

        except Exception, e:
            print_err_detail(e)
            self.set_status(Response.RESULT_SERVERERROR)
            add_err_message_to_response(ret, err_dict['err_mysql'])
    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', '')
        additional_task = self.get_argument('additional_task', '')

        # convert parameters
        additional_task = int(additional_task)

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

        print 'modify additional task'
        print '*' * 100

        try:
            session = Session()

            booking_info = {}

            userdao = UserDAO()
            masterdao = MasterDAO()

            try:
                row = session.query(Booking, UserAddress) \
                             .join(UserAddress, Booking.user_id == UserAddress.user_id) \
                             .filter(Booking.addr_idx == UserAddress.user_addr_index) \
                             .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
Exemple #8
0
    def get(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        date = self.get_argument('date', '')
        sigungu = self.get_argument('sigungu', '')
        customer_sigungu = self.get_argument('customer_sigungu', '')

        if date == None or date == '':
            date = dt.datetime.now()

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

        ret = {}

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

            if sigungu == '':
                master_ids = masterdao.get_all_master_ids()
            else:
                master_ids = masterdao.get_master_ids_where_regions_available(
                    sigungu)

            master_times = []

            day_of_week = date.weekday()

            for mid in master_ids:
                master_schedules = []
                '''start_times, end_times = masterdao.get_master_working_time(mid)

              start_times = start_times.split(',')
              end_times = end_times.split(',')

              st = start_times[day_of_week] if start_times[day_of_week] != '' else 8
              et = end_times[day_of_week] if end_times[day_of_week] != '' else 8

              st = int(st)
              et = int(et)'''

                st, et = masterdao.get_master_working_time_for_day(
                    mid, date.date())
                current_cleaning_counts = masterdao.get_master_completed_cleaning_count_at_date(
                    mid, date)
                is_unassigned = masterdao.is_unassigned(mid)

                master_dict = {}
                master_dict['master_name'] = masterdao.get_master_name(mid)
                master_dict['master_id'] = mid
                master_dict['is_unassigned'] = is_unassigned
                master_dict[
                    'is_beginner'] = True if current_cleaning_counts <= 10 else False
                master_dict[
                    'current_cleaning_counts'] = current_cleaning_counts
                master_dict[
                    'master_available_from'] = '0%s:00' % st if st < 10 else '%s:00' % st
                master_dict[
                    'master_available_to'] = '0%s:00' % et if et < 10 else '%s:00' % et

                # for day off
                master_dict['is_day_off'] = masterdao.is_day_off(
                    mid, date.date())

                for row in session.query(Master, Booking, User, UserAddress, UserDefaultCard, Promotion, EventPromotionBooking) \
                                  .outerjoin(Booking, Master.id == Booking.master_id) \
                                  .join(User, User.id == Booking.user_id) \
                                  .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                                  .outerjoin(UserDefaultCard, User.id == UserDefaultCard.user_id) \
                                  .outerjoin(Promotion, Booking.id == Promotion.booking_id) \
                                  .outerjoin(EventPromotionBooking, Booking.id == EventPromotionBooking.booking_id) \
                                  .filter(func.DATE(Booking.start_time) == date) \
                                  .filter(Master.id == mid) \
                                  .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED, Booking.cleaning_status == BC.BOOKING_COMPLETED)) \
                                  .order_by(Master.name, Booking.start_time) \
                                  .all():

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

                    discount_price = 0
                    if row.Promotion != None:
                        discount_price += row.Promotion.discount_price
                    if row.EventPromotionBooking != None:
                        discount_price += row.EventPromotionBooking.discount_price

                    kind = row.UserAddress.kind
                    if kind == 0:
                        kind = '오피스텔'
                    elif kind == 1:
                        kind = '주택'
                    else:
                        kind = '아파트'

                    address = crypto.decodeAES(row.UserAddress.address)
                    if customer_sigungu in address:
                        master_schedules.append(
                            self.make_schedule_dict(
                                row.Booking.id, row.User.devicetype,
                                row.Booking.appointment_type,
                                row.Booking.appointment_index,
                                dt.datetime.strftime(row.Booking.start_time,
                                                     '%H:%M'),
                                dt.datetime.strftime(
                                    row.Booking.estimated_end_time, '%H:%M'),
                                row.Booking.havereview, row.Booking.user_id,
                                crypto.decodeAES(row.User.name),
                                crypto.decodeAES(row.User.phone),
                                crypto.decodeAES(row.UserAddress.address),
                                row.UserAddress.size, kind,
                                row.Booking.is_dirty, row.Booking.status,
                                row.Booking.cleaning_status,
                                row.Booking.payment_status,
                                row.Booking.price_with_task, discount_price,
                                row.Booking.routing_method, row.User.is_b2b,
                                row.UserDefaultCard))

                master_dict['time_list'] = master_schedules
                master_times.append(master_dict)

            ret['response'] = master_times
            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'])
    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
    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
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
Exemple #12
0
class RatingHandler(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', '')
        c_rate = self.get_argument('clean_rate', 0.0)
        c_review_msg = self.get_argument('clean_review', '')
        m_rate = self.get_argument('master_rate', 0.0)
        m_review_msg = self.get_argument('master_review', '')

        c_rate = float(c_rate)
        m_rate = float(m_rate)

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        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

            master_id = row.master_id
            user_id = row.user_id

            rating = Rating(booking_id=booking_id,
                            master_id=master_id,
                            rate_clean=c_rate,
                            review_clean=c_review_msg,
                            rate_master=m_rate,
                            review_master=m_review_msg,
                            review_time=dt.datetime.now())

            session.add(rating)

            row.havereview = 1  # review flag update

            if c_rate + m_rate == 10:
                master_id = row.master_id
                # 평점 5점 이상 1점 획득
                master_prize = MasterPrize(master_id=master_id,
                                           prize=3000,
                                           prize_description='평점 5점',
                                           earn_date=dt.datetime.now())
                session.add(master_prize)

            session.commit()

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

            mix.track(
                user_id, 'rated', {
                    'time': dt.datetime.now(),
                    'c_rate': c_rate,
                    'm_rate': m_rate,
                    'c_msg': c_review_msg,
                    'm_msg': m_review_msg
                })
            mongo_logger.debug('rated',
                               extra={
                                   'user_id': user_id,
                                   'c_rate': c_rate,
                                   'm_rate': m_rate,
                                   'c_msg': c_review_msg,
                                   'm_msg': m_review_msg
                               })

            #send_rating_granted(booking_id, c_rate, m_rate)

            userdao = UserDAO()
            masterdao = MasterDAO()

            user_name = userdao.get_user_name(user_id)
            master_name = masterdao.get_master_name(master_id)

            #for manager_phone in MANAGERS_CALL.split(','):
            #    send_alimtalk(manager_phone, 'noti_manager_rate', user_name, master_name, c_rate, m_rate)
            send_jandi(
                'NEW_BOOKING', "평가 알림",
                user_name + ' 고객님,' + master_name + '님 평가',
                '클리닝 평가 : {}, 마스터 평가 : {}\n클리닝 평가 내용 : {}\n\n, 마스터 평가 내용 : {}'.
                format(c_rate, m_rate, c_review_msg, m_review_msg))

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

        ret = {}

        uid                         = self.get_argument('uid', '')
        appointment_type            = self.get_argument('appointment_type', BC.ONE_TIME)
        additional_task             = self.get_argument('additional_task', 0)
        date                        = self.get_argument('date', dt.datetime.strftime(dt.datetime.now(), '%Y%m%d'))
        time                        = self.get_argument('time', '08:00')
        taking_time                 = self.get_argument('taking_time', 25)
        first_added_time            = self.get_argument('first_added_time', 0)
        additional_time             = self.get_argument('additional_time', 10)
        have_pet                    = self.get_argument('have_pet', 0)
        master_gender               = self.get_argument('master_gender', 0)
        isdirty                     = self.get_argument('isdirty', 0)
        master_ids                  = self.get_argument('master_ids', [])

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

        appointment_type                = int(appointment_type)
        additional_task                 = int(additional_task)
        taking_time                     = int(taking_time)
        first_added_time                = int(first_added_time)
        additional_time                 = int(additional_time)

        have_pet                        = int(have_pet)
        master_gender                   = int(master_gender) # 0 dont care 1 women
        isdirty                         = int(isdirty)

        print additional_task, type(additional_task)

        if additional_task > 64: # ios typo bug temporary fix
            additional_task = str(additional_task)
            additional_task = int(additional_task, 2)
            if additional_task >= 64:
                additional_task -= 64


        taking_time_in_minutes          = taking_time
        first_added_time_in_minutes     = first_added_time
        additional_time_in_minutes      = additional_time
        total_taking_time_in_minutes    = taking_time_in_minutes + first_added_time_in_minutes + additional_time_in_minutes

        print '*' * 50
        print additional_task
        print '*' * 50

        if isdirty == 1:
            total_taking_time_in_minutes += 120

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

        try:
            booking_info = {}

            masterdao   = MasterDAO()
            holder      = IntermediateValueHolder()

            cal_appointment_type = appointment_type

            if cal_appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                cal_appointment_type = BC.ONE_TIME

            count_of_iteration = cal_appointment_type * 2 + 1 # 2 months

            date_list = []

            if cal_appointment_type == BC.ONE_TIME:
                week_const = 0
            else:
                week_const = 4 / cal_appointment_type

            for i in xrange(count_of_iteration):
                date = selected_date + dt.timedelta(weeks = week_const * i)
                date = dt.datetime.strftime(date, '%Y%m%d')
                date_list.append(date)

            booking_info['dates']            = date_list
            booking_info['time']             = time
            booking_info['appointment_type'] = appointment_type
            booking_info['additional_task']  = additional_task
            booking_info['have_pet']         = have_pet
            booking_info['master_gender']    = master_gender
            booking_info['isdirty']          = isdirty
            booking_info['user_id']          = uid
            booking_info['taking_time']      = taking_time_in_minutes
            booking_info['first_added_time'] = first_added_time_in_minutes
            booking_info['additional_time']  = additional_time_in_minutes
            booking_info['total_time']       = total_taking_time_in_minutes

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

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

                name, img_url, avg_rating   = masterdao.get_master_name_img_and_average_rating(mid)
                booking_info['master_id']   = mid
                booking_info['name']        = name
                booking_info['img_url']     = img_url
                booking_info['avg_rating']  = avg_rating

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

                # 저장할 키 생성
                booking_item_key = '%s_%s_%d' % (uid, 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)

                    booking_info['search_keys'] = master_date_keys
                    booking_info['store_key']   = booking_item_key

                    ret['response'] = booking_info

                    self.set_status(Response.RESULT_OK)

                    # log to mixpanel
                    mix.track(uid, 'select schedule', {'time' : dt.datetime.now(), 'user_id' : uid, 'master_id' : mid, 'sel_date' : selected_date_str, 'sel_time' : time, 'taking_time' : taking_time, 'additional_time' : additional_time, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender,'isdirty' : isdirty})

                    # log to mongo
                    mongo_logger.debug('select schedule', extra = {'user_id' : uid, 'master_id' : mid, 'sel_date' : selected_date_str, 'sel_time' : time, 'taking_time' : taking_time, 'additional_time' : additional_time, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender,'isdirty' : isdirty})
                    return

                i += 1

            # when not available

            # log to mixpanel
            mix.track(uid, 'cannot select schedule admin', {'time' : dt.datetime.now(), 'user_id' : uid, 'sel_date' : selected_date_str, 'sel_time' : time, 'taking_time' : taking_time, 'additional_time' : additional_time, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender,'isdirty' : isdirty})

            # log to mongo
            mongo_logger.debug('cannot select schedule admin', extra = {'log_time' : dt.datetime.now(), 'user_id' : uid, 'sel_date' : selected_date_str, 'sel_time' : time, 'taking_time' : taking_time, 'additional_time' : additional_time, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender,'isdirty' : isdirty})

            # 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

        except Exception, e:
            add_err_message_to_response(ret, err_dict['err_mysql'])
            self.set_status(Response.RESULT_SERVERERROR)
            print_err_detail(e)
            mongo_logger.error('error request select schedules', extra = {'user_id' : uid, 'err' : str(e)})
    def get(self):
        self.set_header("Content-Type", "application/json")
        master_id = self.get_argument('master_id', '')
        year = self.get_argument('yyyy', 2016)
        month = self.get_argument('mm', 9)

        ret = {}

        try:
            session = Session()
            masterdao = MasterDAO()
            userdao = UserDAO()
            bookingdao = BookingDAO()

            CANCELED_RATE = 0.5

            year = int(year)
            month = int(month)

            first_day, last_day = get_month_day_range(dt.date(year, month, 7))

            result = session.query(Booking, Master, User, UserAddress) \
                            .join(Master, Booking.master_id == Master.id) \
                            .join(User, Booking.user_id == User.id) \
                            .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                            .filter(and_(func.date(Booking.start_time) >= first_day, func.date(Booking.start_time) <= last_day)) \
                            .filter(Booking.master_id == master_id) \
                            .order_by(Booking.master_id, Booking.start_time) \
                            .all()

            monthly_salary = 0
            monthly_salaries = []

            for row in result:
                user_name = userdao.get_user_name(row.Booking.user_id)
                org_price = row.Booking.price_with_task
                status = row.Booking.cleaning_status
                appointment_index = row.Booking.appointment_index
                appointment_type = row.Booking.appointment_type
                additional_task = row.Booking.additional_task
                start_time = row.Booking.start_time
                end_time = row.Booking.estimated_end_time
                cleaning_duration = row.Booking.cleaning_duration / 6
                charging_price = row.Booking.charging_price
                is_dirty = row.Booking.is_dirty
                is_b2b = row.User.is_b2b

                duration_in_minutes = (
                    end_time - start_time
                ).seconds / 360  # 계산을 단순하게 하기 위해 60 * 60이 아닌 60 * 6으로 나눔. 그뒤 10배 커지는 것을 방지하기 위해 시급에서 10 나눈 값만 곱함
                minutes_for_salary = duration_in_minutes

                #if duration_in_minutes > cleaning_duration: # 30분의 시간이 더 더해지는 경우가 존재. 그 경우, 해당 시간은 임금에 반영 되지 않음
                #    if appointment_index == 1 and (appointment_type == BC.ONE_TIME_A_MONTH or appointment_type == BC.TWO_TIME_A_MONTH or appointment_type == BC.FOUR_TIME_A_MONTH):
                #        minutes_for_salary = duration_in_minutes - 5

                if is_dirty == 1:  # 똥집인 경우 2시간 제외해야함
                    minutes_for_salary -= 20

                house_type = row.UserAddress.kind
                house_size = row.UserAddress.size

                if row.Booking.cleaning_status == BC.BOOKING_COMPLETED or \
                    row.Booking.cleaning_status == BC.BOOKING_STARTED or \
                    row.Booking.cleaning_status == BC.BOOKING_UPCOMMING:

                    if is_b2b:
                        monthly_salary += int(minutes_for_salary *
                                              (row.Booking.wage_per_hour / 10))
                    else:
                        # 오피스텔 13평 이하, 주택 7평 이하는 시급 14000
                        if appointment_type in BC.REGULAR_CLEANING_DICT:
                            monthly_salary += minutes_for_salary * BC.SALARY_FOR_REGULAR_IN_HOUR
                        else:
                            monthly_salary += minutes_for_salary * BC.SALARY_FOR_ONETIME_IN_HOUR

                        if start_time.weekday(
                        ) in BC.WEEKEND and start_time >= dt.datetime(
                                2016, 12, 17):
                            monthly_salary += BC.WEEKEND_ADDED_SALARY

                    monthly_salary += bookingdao.get_extra_charge(
                        row.Booking.id)

                elif row.Booking.payment_status == BC.BOOKING_CANCELED_CHARGE or \
                    row.Booking.payment_status == BC.BOOKING_CANCELED_REFUND:
                    monthly_salary += int(charging_price * CANCELED_RATE)

            penalty_amount = masterdao.get_master_penalties(
                master_id, first_day, last_day)

            monthly_salary = int(monthly_salary * 0.967)  # 3.3% 제외
            actual_monthly_salary = monthly_salary - penalty_amount

            monthly_salary = '{:,}'.format(monthly_salary)
            actual_monthly_salary = '{:,}'.format(actual_monthly_salary)
            penalty_amount = '{:,}'.format(penalty_amount)

            from_date_str = dt.datetime.strftime(first_day, '%Y%m%d')
            to_date_str = dt.datetime.strftime(last_day, '%Y%m%d')

            monthly_salaries.append({
                'date_from':
                from_date_str,
                'date_to':
                to_date_str,
                'salary':
                monthly_salary,
                'penalty_amount':
                penalty_amount,
                'actual_monthly_salary':
                actual_monthly_salary
            })

            master_row = session.query(Master).filter(
                Master.id == master_id).one()
            master_name = master_row.name
            master_phone = master_row.phone

            ret['response'] = {
                'master_name': master_name,
                'master_phone': master_phone,
                'monthly_salary': monthly_salaries
            }

            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'])
Exemple #15
0
    def get(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

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

        ret = {}

        try:
            session = Session()
            masterdao = MasterDAO()

            try:
                row = session.query(Master, Manager, func.group_concat(MasterPreferedArea.prefered_gu)) \
                         .join(Manager, Master.manager_id == Manager.id) \
                         .outerjoin(MasterPreferedArea, MasterPreferedArea.master_id == Master.id) \
                         .filter(Master.id == master_id) \
                         .group_by(Master.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

            result = session.query(Master, MasterTimeSlot) \
                            .join(MasterTimeSlot, Master.id == MasterTimeSlot.master_id) \
                            .filter(Master.id == master_id) \
                            .order_by(MasterTimeSlot.day_of_week) \
                            .all()

            mid = row.Master.id

            rating_clean, rating_master = masterdao.get_master_rating(mid)
            total_salary = masterdao.get_master_total_granted_salary(mid)
            last_month_salary = masterdao.get_master_last_month_granted_salary(
                mid)
            prefered_area = masterdao.get_master_prefered_area(mid)

            start_times = ['', '', '', '', '', '', '']
            end_times = ['', '', '', '', '', '', '']

            for r in result:
                dow = int(r.MasterTimeSlot.day_of_week)
                start_times[dow] = str(r.MasterTimeSlot.start_time.hour)
                end_times[dow] = str(r.MasterTimeSlot.end_time.hour)

            working_startdate = masterdao.get_master_working_start_date(mid)
            completed_cleaning_count = masterdao.get_master_completed_cleaning_count(
                mid)

            master_info = {}
            master_info['master_id'] = row.Master.id
            master_info['name'] = row.Master.name
            master_info['phone'] = row.Master.phone
            master_info['img'] = row.Master.img_url
            master_info['age'] = row.Master.age
            master_info['gender'] = row.Master.gender
            master_info['pet_alergy'] = row.Master.pet_alergy
            master_info['address'] = row.Master.address
            master_info['manager_name'] = row.Manager.name
            master_info['manager_phone'] = row.Manager.phone
            master_info['cardinal'] = row.Master.cardinal
            master_info['level'] = row.Master.level
            master_info['rating_clean'] = float(rating_clean)
            master_info['rating_master'] = float(rating_master)
            master_info['total_salary'] = int(total_salary)
            master_info['last_month_salary'] = int(last_month_salary)
            master_info[
                'prefered_area'] = prefered_area  # comma separated area
            master_info['cs_prefered_area'] = row[2]  # comma separated area
            master_info['start_times'] = ','.join(
                start_times)  # comma start_time
            master_info['end_times'] = ','.join(end_times)  # comma end_time

            master_info['working_startdate'] = working_startdate
            master_info['cleaning_count'] = completed_cleaning_count

            ret['response'] = master_info
            self.set_status(Response.RESULT_OK)
    def post(self):
        self.set_header("Content-Type", "application/json")

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

        ret = {}

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

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

            content = ''
            result = session.query(Booking, Master, User, UserAddress) \
                            .join(Master, Booking.master_id == Master.id) \
                            .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_COMPLETED)) \
                            .order_by(Booking.start_time) \
                            .all()

            word_idx = 1

            master_name = masterdao.get_master_name(master_id)
            master_phone = masterdao.get_master_phone(master_id)

            for row in result:
                key = userdao.get_user_salt_by_id(row.User.id)[:16]
                crypto = aes.MyCrypto(key)
                master_phone = str(row.Master.phone)
                master_name = str(row.Master.name)
                user_name = str(crypto.decodeAES(row.User.name))
                appointment_index = str(row.Booking.appointment_index)
                enterbuilding = str(
                    crypto.decodeAES(row.Booking.enterbuilding)
                ) if row.Booking.enterbuilding != None else str('')
                enterhome = str(crypto.decodeAES(row.Booking.enterhome)
                                ) if row.Booking.enterhome != None else str('')
                date_str = str(convert_datetime_format2(
                    row.Booking.start_time))
                address = str(crypto.decodeAES(row.UserAddress.address))
                appointment_type    = str(4 / row.Booking.appointment_type) + '주' \
                                      if row.Booking.appointment_type != BC.ONE_TIME \
                                      and row.Booking.appointment_type != BC.ONE_TIME_BUT_CONSIDERING \
                                      else '1회'
                additional_task = additional_task_string(
                    row.Booking.additional_task)
                take_time = timedelta_to_time(row.Booking.estimated_end_time -
                                              row.Booking.start_time)
                take_time_str = '%d시간 %d분' % (take_time.hour, take_time.minute)
                message = str(row.Booking.message)
                trash_location = str(row.Booking.trash_location)

                text = CONFIRM_UPDATE_BODY % (
                    user_name, appointment_index, date_str, address,
                    appointment_type, additional_task, take_time_str,
                    enterbuilding, enterhome, message, trash_location)

                content += str(word_idx) + '. ' + str(text) + '\n\n'
                word_idx += 1

            booking_date = dt.datetime.strftime(date, '%m월%d일')
            title = '%s 홈마스터님, %s 일정입니다.' % (master_name, booking_date)

            if word_idx == 1:
                content = '홈마스터님 내일 일정은 없습니다.'
                title = '홈마스터님 내일 일정은 없습니다.'

            ret['response'] = {
                'content': content,
                'phone': master_phone,
                'subject': title
            }
            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'])
Exemple #17
0
    def get(self):
        self.set_header("Content-Type", "application/json")
        week = self.get_argument('week', 0)  # n weeks before
        week = int(week)

        ret = {}

        FRIDAY = 4
        SATURDAY = 5
        CANCELED_RATE = 0.5

        try:
            session = Session()
            userdao = UserDAO()
            masterdao = MasterDAO()
            bookingdao = BookingDAO()

            # get last saturday
            now = dt.datetime.now()
            if week != 0:
                offset = ((now.weekday() - FRIDAY) % 7) + (week - 1) * 7
                now -= dt.timedelta(days=offset)

            offset = (now.weekday() - SATURDAY) % 7
            last_saturday = (now - dt.timedelta(days=offset)).date()
            now = now.date()

            result = session.query(Booking, Master, User, UserAddress) \
                            .join(Master, Booking.master_id == Master.id) \
                            .join(User, Booking.user_id == User.id) \
                            .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                            .filter(Master.active != 0) \
                            .filter(and_(func.date(Booking.start_time) >= last_saturday, func.date(Booking.start_time) <= now)) \
                            .filter(or_(Booking.cleaning_status == BC.BOOKING_COMPLETED, \
                            and_(Booking.cleaning_status == BC.BOOKING_CANCELED, \
                            or_(Booking.payment_status == BC.BOOKING_CANCELED_REFUND, \
                            Booking.payment_status == BC.BOOKING_CANCELED_CHARGE)))) \
                            .order_by(Booking.master_id, Booking.start_time) \
                            .all()

            weekly_salary = 0

            master_salaries = []

            start_period = last_saturday
            end_period = now

            last_saturday = dt.datetime.strftime(last_saturday, '%Y%m%d')
            now = dt.datetime.strftime(now, '%Y%m%d')

            prev_master_id = None

            for row in result:
                if row.Booking.user_id == '81c2f5c1-7295-489d-8bb0-334121060ae3':
                    continue

                user_name = userdao.get_user_name(row.Booking.user_id)
                org_price = row.Booking.price_with_task
                status = row.Booking.cleaning_status
                appointment_index = row.Booking.appointment_index
                appointment_type = row.Booking.appointment_type
                start_time = row.Booking.start_time
                end_time = row.Booking.estimated_end_time
                cleaning_duration = row.Booking.cleaning_duration / 6
                charging_price = row.Booking.charging_price
                is_dirty = row.Booking.is_dirty
                is_b2b = row.User.is_b2b

                duration_in_minutes = (
                    end_time - start_time
                ).seconds / 360  # 계산을 단순하게 하기 위해 60 * 60이 아닌 60 * 6으로 나눔. 그뒤 10배 커지는 것을 방지하기 위해 시급에서 10 나눈 값만 곱함
                minutes_for_salary = duration_in_minutes

                #if duration_in_minutes > cleaning_duration: # 30분의 시간이 더 더해지는 경우가 존재. 그 경우, 해당 시간은 임금에 반영 되지 않음
                #    if appointment_index == 1 and (appointment_type == BC.ONE_TIME_A_MONTH or appointment_type == BC.TWO_TIME_A_MONTH or appointment_type == BC.FOUR_TIME_A_MONTH):
                #        minutes_for_salary = duration_in_minutes - 5

                if is_dirty == 1:
                    minutes_for_salary -= 20

                house_type = row.UserAddress.kind
                house_size = row.UserAddress.size

                extra_charge = 0
                if row.Booking.cleaning_status == BC.BOOKING_COMPLETED:
                    if is_b2b:
                        weekly_salary = int(minutes_for_salary *
                                            (row.Booking.wage_per_hour / 10))
                    else:
                        # 오피스텔 13평 이하, 주택 7평 이하는 시급 14000
                        weekly_salary = 0
                        if start_time >= dt.datetime(2017, 1, 1):
                            weekly_salary = minutes_for_salary * BC.SALARY_FOR_ONETIME_IN_HOUR
                        else:
                            if appointment_type in BC.REGULAR_CLEANING_DICT:
                                weekly_salary = minutes_for_salary * BC.SALARY_FOR_REGULAR_IN_HOUR
                            else:
                                weekly_salary = minutes_for_salary * BC.SALARY_FOR_ONETIME_IN_HOUR

                        if start_time.weekday(
                        ) in BC.WEEKEND and start_time >= dt.datetime(
                                2016, 12, 17):
                            weekly_salary += BC.WEEKEND_ADDED_SALARY

                    extra_charge = bookingdao.get_extra_charge(row.Booking.id)
                    weekly_salary += extra_charge

                elif row.Booking.payment_status == BC.BOOKING_CANCELED_CHARGE or \
                    row.Booking.payment_status == BC.BOOKING_CANCELED_REFUND:
                    weekly_salary = int(charging_price * CANCELED_RATE)

                if prev_master_id == None or prev_master_id != row.Booking.master_id:  # 변함
                    salary = {}
                    salary_detail = []
                    bank_name, bank_code, account_no = masterdao.get_master_account(
                        row.Booking.master_id)

                    salary['weekly_salary'] = 0
                    salary['master_name'] = row.Master.name
                    salary['master_account'] = {
                        'bank_name': bank_name,
                        'bank_code': bank_code,
                        'account_no': account_no
                    }
                    salary['master_phone'] = row.Master.phone
                    salary['weekly_salary'] += weekly_salary
                    salary[
                        'penalty_amount'] = 0  #masterdao.get_master_penalties(row.Booking.master_id, start_period, end_period)

                    if weekly_salary > 0:
                        salary_detail.append({
                            'org_price':
                            org_price,
                            'charging_price':
                            charging_price,
                            'salary':
                            weekly_salary,
                            'extra_charge':
                            extra_charge,
                            'status':
                            status,
                            'start_time':
                            dt.datetime.strftime(start_time, '%Y-%m-%d %H:%M'),
                            'end_time':
                            dt.datetime.strftime(end_time, '%Y-%m-%d %H:%M'),
                            'cleaning_index':
                            appointment_index,
                            'user_name':
                            user_name
                        })

                    salary['salary_detail'] = salary_detail

                    master_salaries.append(salary)
                else:
                    salary['weekly_salary'] += weekly_salary
                    if weekly_salary > 0:
                        salary_detail.append({
                            'org_price':
                            org_price,
                            'charging_price':
                            charging_price,
                            'salary':
                            weekly_salary,
                            'extra_charge':
                            extra_charge,
                            'status':
                            status,
                            'start_time':
                            dt.datetime.strftime(start_time, '%Y-%m-%d %H:%M'),
                            'end_time':
                            dt.datetime.strftime(end_time, '%Y-%m-%d %H:%M'),
                            'cleaning_index':
                            appointment_index,
                            'user_name':
                            user_name
                        })

                prev_master_id = row.Master.id

            total_salaries = 0
            for ms in master_salaries:
                if start_time >= dt.datetime(2017, 1, 1):
                    ms['weekly_salary'] = int(ms['weekly_salary'])
                else:
                    ms['weekly_salary'] = int(ms['weekly_salary'] * 0.967)
                total_salaries += (ms['weekly_salary'] - ms['penalty_amount'])
                ms['actual_weekly_salary'] = '{:,}'.format(
                    ms['weekly_salary'] - ms['penalty_amount'])

            total_salaries = '{:,}'.format(total_salaries)

            master_salaries = sorted(master_salaries,
                                     key=lambda x: (x['master_name']))

            ret['response'] = {
                'date_from': last_saturday,
                'date_to': now,
                'master_salaries': master_salaries,
                'total_salaries': total_salaries
            }
            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'])
Exemple #18
0
    def post(self):
        self.set_header("Content-Type", "application/json")

        ret = {}

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

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

        keys = comb_key.split('_')

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

        try:
            booking_info = {}

            masterdao   = MasterDAO()
            holder      = IntermediateValueHolder()

            print comb_key
            appointment_type = int(comb_key.split('_')[2])

            date_list = []

            if appointment_type == BC.ONE_TIME:
                count_of_iteration = 1
                week_const = 0
            else:
                count_of_iteration = appointment_type * 2 # 2 months
                week_const = 4 / appointment_type

            for i in xrange(count_of_iteration):
                date = selected_date + dt.timedelta(weeks = week_const * i)
                date = dt.datetime.strftime(date, '%Y%m%d')
                date_list.append(date)

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

            house_type       = comb_key.split('_')[0]
            if house_type == 'officetel':
                house_type = 0
            elif house_type == 'rowhouse':
                house_type = 1
            else:
                house_type = 2

            house_type       = int(house_type)
            house_size       = int(comb_key.split('_')[1])
            additional_task  = int(comb_key.split('_')[3])

            print comb_key
            print appointment_type, house_type, house_size
            _, cleaning_duration, _, _ = get_time_price(appointment_type, house_type, house_size)
            booking_info['cleaning_duration'] = cleaning_duration

            task_time, _ = get_additional_task_time_price(additional_task, house_type, house_size)
            booking_info['additional_time'] = task_time
            print task_time

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

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

                name, img_url, avg_rating   = masterdao.get_master_name_img_and_average_rating(mid)
                booking_info['master_id']   = mid
                booking_info['name']        = name
                booking_info['img_url']     = img_url
                booking_info['avg_rating']  = avg_rating

                now = dt.datetime.strftime(dt.datetime.now(), '%Y%m%d%H%M%S')
                hashids = Hashids(min_length = 16, salt = now + comb_key)
                booking_id = hashids.encode(int(date + time.replace(':', '')))
                booking_info['id']  = booking_id

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

                # 저장할 키 생성
                #booking_item_key = '%s_%s' % (comb_key, master_date_keys[0])

                if holder.store_keys(master_date_keys, source = '11st') and not masterdao.is_master_off_date(mid, selected_date.date()): # 메모리에 키가 하나도 없을 때, 즉 예약이 가능할 때
                    master_date_keys = ','.join(master_date_keys)
                    booking_info['search_keys'] = master_date_keys
                    booking_info['store_key']   = booking_id  # 11번가의 경우는, 미리 생성한 아이디 키로 한다.

                    holder.store(booking_id, booking_info, source = '11st')

                    # for 11st response
                    ret['response'] = {'booking_available' : 'Y', 'booking_id' : booking_id}

                    self.set_status(Response.RESULT_OK)

                    # log to mixpanel
                    #mix.track(uid, '11 select schedule', {'time' : dt.datetime.now(), 'user_id' : uid, 'master_id' : mid, 'sel_date' : selected_date_str, 'sel_time' : time, 'taking_time' : taking_time, 'additional_time' : additional_time, 'appointment_type' : appointment_type, 'have_pet' : have_pet, 'master_gender' : master_gender,'isdirty' : isdirty})

                    # log to mongo
                    mongo_logger.debug('11 select schedule', extra = {'master_id' : mid, 'sel_date' : selected_date_str, 'sel_time' : time, 'comb_key' : comb_key})
                    return

                i += 1

            # when not available
            # log to mongo
            mongo_logger.debug('11 cannot select schedule', extra = {'sel_date' : selected_date_str, 'sel_time' : time, 'comb_key' : comb_key})

            # other users preempt homemasters, so no homemaster available
            self.set_status(Response.RESULT_OK)

            ret['response'] = {'booking_available' : 'N'}

            return

        except Exception, e:
            add_err_message_to_response(ret, err_dict['err_mysql'])
            self.set_status(Response.RESULT_SERVERERROR)
            print_err_detail(e)
            mongo_logger.error('error 11 request select schedules', extra = {'err' : str(e)})
    def get(self):
        self.set_header("Content-Type", "application/json")
        year = self.get_argument('yyyy', 2016)
        month = self.get_argument('mm', 9)

        ret = {}

        try:
            session = Session()
            masterdao = MasterDAO()
            userdao = UserDAO()
            bookingdao = BookingDAO()

            CANCELED_RATE = 0.5

            year = int(year)
            month = int(month)

            first_day, last_day = get_month_day_range(dt.date(year, month, 7))

            result = session.query(Booking, Master, User, UserAddress) \
                            .join(Master, Booking.master_id == Master.id) \
                            .join(User, Booking.user_id == User.id) \
                            .join(UserAddress, and_(Booking.user_id == UserAddress.user_id, Booking.addr_idx == UserAddress.user_addr_index)) \
                            .filter(and_(func.date(Booking.start_time) >= first_day, func.date(Booking.start_time) <= last_day)) \
                            .filter(Master.active == 1) \
                            .order_by(Booking.master_id, Booking.start_time) \
                            .all()

            monthly_salary_dict = {}
            prev_master_id = None

            for row in result:
                user_name = userdao.get_user_name(row.Booking.user_id)
                master_id = row.Booking.master_id
                master_name = row.Master.name
                master_phone = row.Master.phone
                org_price = row.Booking.price_with_task
                status = row.Booking.cleaning_status
                #appointment_index   = row.Booking.appointment_index
                appointment_type = row.Booking.appointment_type
                additional_task = row.Booking.additional_task
                start_time = row.Booking.start_time
                end_time = row.Booking.estimated_end_time
                #cleaning_duration   = row.Booking.cleaning_duration / 6
                charging_price = row.Booking.charging_price
                is_dirty = row.Booking.is_dirty
                is_b2b = row.User.is_b2b

                duration_in_minutes = (
                    end_time - start_time
                ).seconds / 360  # 계산을 단순하게 하기 위해 60 * 60이 아닌 60 * 6으로 나눔. 그뒤 10배 커지는 것을 방지하기 위해 시급에서 10 나눈 값만 곱함
                minutes_for_salary = duration_in_minutes

                #if duration_in_minutes > cleaning_duration: # 30분의 시간이 더 더해지는 경우가 존재. 그 경우, 해당 시간은 임금에 반영 되지 않음
                #    if appointment_index == 1 and (appointment_type == BC.ONE_TIME_A_MONTH or appointment_type == BC.TWO_TIME_A_MONTH or appointment_type == BC.FOUR_TIME_A_MONTH):
                #        minutes_for_salary = duration_in_minutes - 5

                monthly_salary = 0

                if is_dirty == 1:  # 똥집인 경우 2시간 제외해야함
                    minutes_for_salary -= 20

                house_type = row.UserAddress.kind
                house_size = row.UserAddress.size

                if row.Booking.cleaning_status == BC.BOOKING_COMPLETED or \
                    row.Booking.cleaning_status == BC.BOOKING_STARTED or \
                    row.Booking.cleaning_status == BC.BOOKING_UPCOMMING:

                    if is_b2b:
                        monthly_salary = int(minutes_for_salary *
                                             (row.Booking.wage_per_hour / 10))
                    else:
                        # 오피스텔 13평 이하, 주택 7평 이하는 시급 14000
                        if appointment_type in BC.REGULAR_CLEANING_DICT:
                            monthly_salary = minutes_for_salary * BC.SALARY_FOR_REGULAR_IN_HOUR
                        else:
                            monthly_salary = minutes_for_salary * BC.SALARY_FOR_ONETIME_IN_HOUR

                        if start_time.weekday(
                        ) in BC.WEEKEND and start_time >= dt.datetime(
                                2016, 12, 17):
                            monthly_salary += BC.WEEKEND_ADDED_SALARY

                    monthly_salary += bookingdao.get_extra_charge(
                        row.Booking.id)

                elif row.Booking.payment_status == BC.BOOKING_CANCELED_CHARGE or \
                    row.Booking.payment_status == BC.BOOKING_CANCELED_REFUND:
                    monthly_salary = int(charging_price * CANCELED_RATE)

                monthly_salary = monthly_salary * 0.967  # 3.3% 제외

                # 마스터가 신규
                if prev_master_id == None or master_id != prev_master_id:
                    penalty_amount = masterdao.get_master_penalties(
                        master_id, first_day, last_day)
                    monthly_salary_dict[master_id] = {
                        'name': master_name,
                        'phone': master_phone,
                        'monthly_salary': monthly_salary,
                        'penalty_amount': penalty_amount
                    }
                else:
                    monthly_salary_dict[master_id][
                        'monthly_salary'] += monthly_salary

                prev_master_id = master_id

            monthly_salary_dict = {value['name'] : {'master_id' : mid, \
                                                    'phone' : value['phone'], \
                                                    'monthly_salary' : int(value['monthly_salary']), \
                                                    'monthly_salary_str' : '{:,}'.format(int(value['monthly_salary'])), \
                                                    'penalty_amount' : value['penalty_amount']} \
                                    for mid, value in monthly_salary_dict.items()}

            monthly_salary_dict = OrderedDict(
                sorted(monthly_salary_dict.items(), key=lambda x: x[0]))

            ret['response'] = monthly_salary_dict

            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'])
Exemple #20
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'])
Exemple #21
0
    def get(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        ret = {}

        try:
            session = Session()
            masterdao = MasterDAO()

            masters = []

            master_ids = masterdao.get_all_master_ids()
            for mid in master_ids:
                master_info = {}

                basic = masterdao.get_master_basic_info(mid)
                rating_clean, rating_master = masterdao.get_master_rating(mid)
                total_salary = masterdao.get_master_total_granted_salary(mid)
                last_month_salary = masterdao.get_master_last_month_granted_salary(
                    mid)
                prefered_area = masterdao.get_master_prefered_area(mid)
                start_times, end_times = masterdao.get_master_working_time(mid)

                working_startdate = masterdao.get_master_working_start_date(
                    mid)
                completed_cleaning_count = masterdao.get_master_completed_cleaning_count(
                    mid)

                bank_name, bank_code, account_no = masterdao.get_master_account(
                    mid)

                master_info['master_id'] = mid
                master_info['name'] = basic['name']
                master_info['phone'] = basic['phone']
                master_info['img'] = basic['img']
                master_info['age'] = basic['age']
                master_info['gender'] = basic['gender']
                master_info['address'] = basic['address']
                master_info['pet_alergy'] = basic['pet_alergy']
                master_info['manager_name'] = basic['manager_name']
                master_info['manager_phone'] = basic['manager_phone']
                master_info['cardinal'] = basic['cardinal']
                master_info['level'] = basic['level']
                master_info['need_route'] = basic['need_route']
                master_info['t_size'] = basic['t_size']
                master_info['rating_clean'] = float(rating_clean)
                master_info['rating_master'] = float(rating_master)
                master_info['total_salary'] = int(total_salary)
                master_info['last_month_salary'] = int(last_month_salary)
                master_info['prefered_area'] = prefered_area
                master_info['prefered_area_list'] = [
                    area for area in prefered_area.split(',')
                ]
                master_info['start_times'] = start_times
                master_info['end_times'] = end_times
                master_info['active'] = basic['active']

                master_info['working_startdate'] = working_startdate
                master_info['cleaning_count'] = completed_cleaning_count
                master_info['account'] = {
                    'name': bank_name,
                    'code': bank_code,
                    'account_no': account_no
                }

                masters.append(master_info)

            ret['response'] = masters
            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'])
    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        booking_id = self.get_argument('booking_id', '')
        reason_id = self.get_argument('reason_id', CANCEL_ADMIN)
        etc_reason = self.get_argument('etc_reason', '')
        no_fee = self.get_argument('no_fee', 0)

        reason_id = int(reason_id)

        print "reason_id : ", reason_id

        no_fee = int(no_fee)

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        try:
            session = Session()

            try:
                row = session.query(Booking, Master, User, UserAddress) \
                             .join(Master, Booking.master_id == Master.id) \
                             .join(User, Booking.user_id == User.id) \
                             .join(UserDefaultAddress, User.id == UserDefaultAddress.user_id) \
                             .join(UserAddress, and_(UserAddress.user_id == UserDefaultAddress.user_id, UserAddress.user_addr_index == UserDefaultAddress.address_idx)) \
                             .filter(Booking.id == booking_id) \
                             .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                             .one()

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

            user_id = row.Booking.user_id

            masterdao = MasterDAO()
            userdao = UserDAO()
            key = userdao.get_user_salt_by_id(user_id)[:16]
            crypto = aes.MyCrypto(key)

            # push to homemaster via sms
            master_id = row.Master.id

            master_phone = str(row.Master.phone)
            master_name = str(row.Master.name)
            username = str(crypto.decodeAES(row.User.name))
            userphone = str(crypto.decodeAES(row.User.phone))
            date = str(convert_datetime_format(row.Booking.start_time))
            addr = str(crypto.decodeAES(row.UserAddress.address))

            charge = 0
            new_status = BC.BOOKING_CANCELED_CHARGE

            request_id = row.Booking.request_id

            appointment_index = row.Booking.appointment_index
            appointment_time = row.Booking.start_time
            appointment_type = row.Booking.appointment_type
            current_status = row.Booking.status
            current_cleaning_status = row.Booking.cleaning_status
            current_payment_status = row.Booking.payment_status
            price = row.Booking.price_with_task
            source = row.Booking.source
            device_type = row.Booking.user_type
            now = dt.datetime.now()
            cancel_amount = 0

            diff_in_hours = (appointment_time - now).total_seconds() / 3600

            if diff_in_hours >= 24:
                charge = price * BC.BOOKING_CHARGE_RATE_NO
            elif 4 <= diff_in_hours < 24:
                charge = price * BC.BOOKING_CHARGE_RATE_30
            else:
                charge = price * BC.BOOKING_CHARGE_RATE_50

            if current_payment_status == BC.BOOKING_PAID:
                if no_fee == 1:  # 관리자가 선택하여 fee를 지불 할 수 있게 하기 위해서
                    charge = 0

                new_status = BC.BOOKING_CANCELED_REFUND

                partial = '1'
                if charge == 0:
                    partial = '0'

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

                is_event = True if is_event != None else False

                cancel_amount = int(price - charge)
                if cancel_amount > 0 and source == 'hm' and userdao.get_user_default_card_index(
                        user_id) != -1:
                    if not (is_event and appointment_index == 1):
                        ret_code, msg = cancel_payment(user_id, booking_id,
                                                       cancel_amount, partial)
                        if ret_code == False:
                            session.close()
                            self.set_status(Response.RESULT_OK)
                            add_err_ko_message_to_response(ret, msg)
                            #self.write(json.dumps(ret))
                            return
                    else:
                        # 결제 필요
                        # 취소에 대한 결제 필요
                        partial = '0'
                        cancel_amount = row.Booking.price_with_task - row.Booking.price
                        if cancel_amount > 0:
                            cancel_payment(user_id, booking_id, cancel_amount,
                                           partial)

                        complete_count = session.query(Booking) \
                                .filter(Booking.request_id == request_id) \
                                .filter(Booking.cleaning_status == 2) \
                                .count()

                        print complete_count, row.Booking.cleaning_status
                        if complete_count < 9 and row.Booking.cleaning_status == 2:
                            ret_code, msg = request_payment(
                                user_id, username, booking_id, price,
                                appointment_type)
                            if ret_code == False:
                                row.Booking.payment_status = BC.BOOKING_PAYMENT_FAILED

            else:  # cancel charge price
                print 'cancel charge'
                charging_price = int(charge)
                if charging_price > 0 and source == 'hm' and userdao.get_user_default_card_index(
                        user_id) != -1 and no_fee == 0:
                    print user_id, username, booking_id, charging_price, appointment_type

                    ret_code, msg = request_payment(user_id, username,
                                                    booking_id, charging_price,
                                                    appointment_type)
                    if ret_code == False:
                        new_status = BC.BOOKING_PAYMENT_FAILED

            #row.Booking.modified_date   = now
            row.Booking.charging_price = int(charge)
            row.Booking.status = new_status
            row.Booking.cleaning_status = BC.BOOKING_CANCELED
            row.Booking.payment_status = new_status

            appointment_type_text = ''
            if appointment_type == BC.ONE_TIME or appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                appointment_type_text = '1회'
            elif appointment_type == BC.FOUR_TIME_A_MONTH:
                appointment_type_text = '매주'
            elif appointment_type == BC.TWO_TIME_A_MONTH:
                appointment_type_text = '2주 1회'
            elif appointment_type == BC.ONE_TIME_A_MONTH:
                appointment_type_text = '4주 1회'

            #sms_sender = SMS_Sender()
            #text = BOOKING_CANCEL_TEXT % (username, userphone, master_name, date)
            #print sms_sender.send_for_manager(sender = MAIN_CALL, mtype = 'sms', to = MANAGERS_CALL, subject = BOOKING_TEXT_SUBJECT, text = text)
            #for manager_phone in MANAGERS_CALL.split(','):
            #    send_alimtalk(manager_phone, 'noti_manager_cancel', username, date, appointment_type_text)

            cancel_reasons = []
            cancel_reasons.append('지금은 서비스가 필요하지 않아요')
            cancel_reasons.append('집에 없어서 문을 열어드릴 수가 없어요')
            cancel_reasons.append('시간이 마음에 들지 않아요')
            cancel_reasons.append('클리닝을 잊고 있었네요')
            cancel_reasons.append('원하는 홈마스터가 아니에요')
            cancel_reasons.append('기타')
            cancel_reasons.append('이사가요')
            cancel_reasons.append('기타')
            cancel_reasons.append('관리자가 취소 했습니다')

            cancel_reason = cancel_reasons[reason_id]
            if cancel_reason == '기타':
                cancel_reason += ' ' + etc_reason
            elif reason_id == CANCEL_ADMIN:
                cancel_reason += ', 관리자 메모 : ' + etc_reason

            send_jandi(
                'NEW_BOOKING', "취소 알림", username + ' 고객님 취소함',
                '{}, {}, 사유 : {}'.format(date, appointment_type_text,
                                         cancel_reason))
            print 'jandi notification for cancel...'

            master_pushkey = masterdao.get_master_pushkey(master_id)
            #master_name = masterdao.get_master_name(master_id)
            #master_phone   = masterdao.get_master_phone(master_id)

            send_booking_canceled('android', [master_pushkey], booking_id,
                                  date, username)

            content = '''{} 홈마스터님
예약이 1회 취소 되었습니다.

고객 : {}
주기 : {}
날짜 : {}'''.format(master_name, username, appointment_type_text, date)

            message_sender = MessageSender()
            message_sender.send([master_phone], '예약 1회 취소 알림', content)

            print 'master_pushkey', master_pushkey
            print booking_id, date

            #send_alimtalk(master_phone, 'noti_manager_cancel', username, date, appointment_type_text)
            # adjust appointment index
            index_result = session.query(Booking).filter(
                Booking.request_id == request_id).filter(
                    Booking.appointment_index > appointment_index).all()
            for index_row in index_result:
                index_row.appointment_index -= 1

            coupondao = CouponDAO()
            coupondao.cancel_coupon_usage(booking_id)

            CANCEL = 0
            cancel_reason = CancelReason(booking_id=booking_id,
                                         user_id=user_id,
                                         reason_id=reason_id,
                                         etc_reason=etc_reason,
                                         kind=CANCEL,
                                         cancel_time=dt.datetime.now())
            session.add(cancel_reason)

            session.commit()

            mix.track(
                user_id, 'cancel', {
                    'time': dt.datetime.now(),
                    'reason_id': reason_id,
                    'etc_reason': etc_reason,
                    'cancel_amount': cancel_amount
                })
            mongo_logger.debug('%s was canceled' % booking_id,
                               extra={
                                   'user_id': user_id,
                                   'booking_id': booking_id,
                                   'cancel_amount': cancel_amount
                               })

            ret['response'] = Response.SUCCESS

            self.set_status(Response.RESULT_OK)
    def post(self):
        self.set_header("Content-Type", "application/json")
        booking_id = self.get_argument('booking_id', '')
        reason_id = self.get_argument('reason_id', 0)
        etc_reason = self.get_argument('etc_reason', '')

        reason_id = int(reason_id)

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        try:
            session = Session()

            try:
                row = session.query(Booking, Master, User, UserAddress) \
                             .join(Master, Booking.master_id == Master.id) \
                             .join(User, Booking.user_id == User.id) \
                             .join(UserDefaultAddress, User.id == UserDefaultAddress.user_id) \
                             .join(UserAddress, and_(UserAddress.user_id == UserDefaultAddress.user_id, UserAddress.user_addr_index == UserDefaultAddress.address_idx)) \
                             .filter(Booking.id == booking_id) \
                             .filter(Booking.cleaning_status == BC.BOOKING_UPCOMMING) \
                             .one()

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

            charge = 0
            new_status = BC.BOOKING_CANCELED_CHARGE

            request_id = row.Booking.request_id
            user_id = row.Booking.user_id
            appointment_index = row.Booking.appointment_index
            appointment_time = row.Booking.start_time
            appointment_type = row.Booking.appointment_type
            current_status = row.Booking.status
            current_cleaning_status = row.Booking.cleaning_status
            current_payment_status = row.Booking.payment_status
            price = row.Booking.price_with_task
            now = dt.datetime.now()

            diff_in_hours = (appointment_time - now).total_seconds() / 3600

            if diff_in_hours >= 24:
                charge = price * BC.BOOKING_CHARGE_RATE_NO
            elif 4 <= diff_in_hours < 24:
                charge = price * BC.BOOKING_CHARGE_RATE_30
            else:
                charge = price * BC.BOOKING_CHARGE_RATE_50

            if current_payment_status == BC.BOOKING_PAID:
                new_status = BC.BOOKING_CANCELED_REFUND
                '''
                partial = '1'
                if charge == 0:
                    partial = '0'

                cancel_amount = int(price - charge)
                if cancel_amount > 0:
                    ret_code, msg = cancel_payment(user_id, booking_id, cancel_amount, partial)
                    if ret_code == False:
                        session.close()
                        self.set_status(Response.RESULT_OK)
                        add_err_ko_message_to_response(ret, msg)
                        self.write(json.dumps(ret))
                        return'''

            #row.Booking.modified_date   = now
            row.Booking.charging_price = int(charge)
            row.Booking.status = new_status
            row.Booking.cleaning_status = BC.BOOKING_CANCELED
            row.Booking.payment_status = new_status

            masterdao = MasterDAO()
            userdao = UserDAO()
            key = userdao.get_user_salt_by_id(user_id)[:16]
            crypto = aes.MyCrypto(key)

            # push to homemaster via sms
            master_id = row.Master.id
            master_phone = str(row.Master.phone)
            master_name = str(row.Master.name)
            username = str(crypto.decodeAES(row.User.name))
            userphone = str(crypto.decodeAES(row.User.phone))
            date = str(convert_datetime_format(row.Booking.start_time))
            addr = str(crypto.decodeAES(row.UserAddress.address))

            appointment_type_text = ''
            if appointment_type == BC.ONE_TIME or appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                appointment_type_text = '1회'
            elif appointment_type == BC.FOUR_TIME_A_MONTH:
                appointment_type_text = '매주'
            elif appointment_type == BC.TWO_TIME_A_MONTH:
                appointment_type_text = '2주 1회'
            elif appointment_type == BC.ONE_TIME_A_MONTH:
                appointment_type_text = '4주 1회'

            #sms_sender = SMS_Sender()
            #text = BOOKING_CANCEL_TEXT % (username, userphone, master_name, date)
            #print sms_sender.send_for_manager(sender = MAIN_CALL, mtype = 'sms', to = MANAGERS_CALL, subject = BOOKING_TEXT_SUBJECT, text = text)
            for manager_phone in MANAGERS_CALL.split(','):
                send_alimtalk(manager_phone, 'noti_manager_cancel', username,
                              date, appointment_type_text)

            master_pushkey = masterdao.get_master_pushkey(master_id)
            #send_booking_canceled('android', [master_pushkey], booking_id, date)

            print 'master_pushkey', master_pushkey
            print booking_id, date

            #send_alimtalk(master_phone, 'noti_manager_cancel', username, date, appointment_type_text)

            # adjust appointment index
            index_result = session.query(Booking).filter(
                Booking.request_id == request_id).filter(
                    Booking.appointment_index > appointment_index).all()
            for index_row in index_result:
                index_row.appointment_index -= 1

            CANCEL = 0
            cancel_reason = CancelReason(booking_id=booking_id,
                                         user_id=user_id,
                                         reason_id=reason_id,
                                         etc_reason=etc_reason,
                                         kind=CANCEL,
                                         cancel_time=dt.datetime.now())
            session.add(cancel_reason)

            session.commit()

            mix.track(
                user_id, 'cancel', {
                    'time': dt.datetime.now(),
                    'reason_id': reason_id,
                    'etc_reason': etc_reason
                })
            mongo_logger.debug('%s was canceled' % booking_id,
                               extra={
                                   'user_id': user_id,
                                   'booking_id': booking_id
                               })

            ret['response'] = Response.SUCCESS
            self.set_status(Response.RESULT_OK)
    def post(self):
        self.set_header("Content-Type", "application/json")

        ret = {}

        uid = self.get_argument('uid', '')
        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)
        appointment_type = self.get_argument('appointment_type', BC.ONE_TIME)
        taking_time = self.get_argument('taking_time', 25)
        first_added_time = self.get_argument('first_added_time', 0)
        additional_time = self.get_argument('additional_time', 10)
        have_pet = self.get_argument('have_pet', 0)
        master_gender = self.get_argument('master_gender', 0)
        isdirty = self.get_argument('isdirty', 0)

        # convert datetime
        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 = int(appointment_type)
        taking_time = int(taking_time)
        first_added_time = int(first_added_time)
        additional_time = int(additional_time)

        taking_time_in_minutes = taking_time * 6
        first_added_time_in_minutes = first_added_time * 6
        additional_time_in_minutes = additional_time * 6
        total_taking_time_in_minutes = taking_time_in_minutes + first_added_time_in_minutes + additional_time_in_minutes

        have_pet = int(have_pet)
        master_gender = int(master_gender)  # 0 dont care 1 women 2 men
        isdirty = int(isdirty)

        print 'request schedule'
        print 'taking time :', taking_time_in_minutes

        mongo_logger = get_mongo_logger()

        mongo_logger.debug('%s request schedule' % uid,
                           extra={
                               'date': dt.datetime.strftime(date, '%Y%m%d'),
                               'start_time_range_begin':
                               start_time_range_begin,
                               'start_time_range_end': start_time_range_end,
                               'taking_time': taking_time,
                               'additional_time': additional_time,
                               'appointment_type': appointment_type,
                               'have_pet': have_pet,
                               'master_gender': master_gender,
                               'isdirty': isdirty
                           })

        mix = get_mixpanel()

        try:
            session = Session()

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

            holder = IntermediateValueHolder()

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

            # get user's address and cover address to gu code
            address, geohash5, geohash6 = userdao.get_user_address(uid)
            gu_id = addrdao.get_gu_id(address)

            # four consecutive appointment days to make booking if regular , otherwise just one day
            dates = [int(dt.datetime.strftime(date, '%Y%m%d'))]

            if appointment_type == BC.ONE_TIME_A_MONTH or appointment_type == BC.TWO_TIME_A_MONTH or appointment_type == BC.FOUR_TIME_A_MONTH:
                dates = [
                    int(
                        dt.datetime.strftime(
                            date + dt.timedelta(days=i * BC.DAYS_IN_A_WEEK *
                                                (4 / appointment_type)),
                            '%Y%m%d')) for i in xrange(4)
                ]

            # 크리스마스 및 새해 임시로 막음.
            if date.date() == dt.date(2016, 2, 7) or date.date() == dt.date(
                    2016, 2, 8) or date.date() == dt.date(
                        2016, 2, 9) or date.date() == dt.date(2016, 2, 10):
                self.set_status(Response.RESULT_OK)
                add_err_ko_message_to_response(ret, '설날 연휴동안은, 예약이 불가능합니다.')
                self.write(json.dumps(ret))
                return

            # 스케쥴이 이미 해당 날짜에 있다면, 있다고 표시하고 리턴함
            num_schedules_on_dates = userdao.get_user_schedule_on_dates(
                uid,
                [dt.datetime.strptime(str(d), '%Y%m%d').date() for d in dates])
            if num_schedules_on_dates > 0:
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret,
                                            err_dict['err_schedules_on_dates'])
                self.write(json.dumps(ret))
                return

            # 똥집인 경우 3시간 추가됨.
            if isdirty == 1:
                if appointment_type == BC.ONE_TIME or appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                    total_taking_time_in_minutes += 120

            print 'gu_id', gu_id, have_pet, master_gender, dates

            #get available homemaster's time table day by day
            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, \
                                                total_taking_time_in_minutes, \
                                                geohash6)

            # if not successful
            if success != 'SUCCESS':
                self.set_status(Response.RESULT_OK)
                add_err_message_to_response(ret,
                                            err_dict['err_no_hm_at_that_time'])
                mix.track(
                    uid, 'request schedule', {
                        'time': dt.datetime.now(),
                        'date': dt.datetime.strftime(date, '%Y%m%d'),
                        'start_time_range_begin': start_time_range_begin,
                        'start_time_range_begin_min':
                        start_time_range_begin_min,
                        'start_time_range_end': start_time_range_end,
                        'start_time_range_end_min': start_time_range_end_min,
                        'taking_time': taking_time,
                        'additional_time': additional_time,
                        'appointment_type': appointment_type,
                        'have_pet': have_pet,
                        'master_gender': master_gender,
                        'isdirty': isdirty,
                        'status': 'no homemaster'
                    })
                print uid, 'was not able to find any homemasters....'
            else:
                schedules = []

                for row in result:
                    s = {}
                    s['date'] = row['date']
                    s['start_time'] = time_to_str(row['start_time'])
                    s['end_time'] = time_to_str(row['end_time'])

                    schedules.append(s)

                mid = row['mid']
                name, img_url, avg_rating = masterdao.get_master_name_img_and_average_rating(
                    mid)

                search_keys_str = ','.join(search_keys)
                ret['response'] = {
                    'store_key': store_key,
                    'search_keys': search_keys_str,
                    'schedules': schedules,
                    'uid': uid,
                    'mid': row['mid'],
                    'name': name,
                    'img_url': img_url,
                    'avg_rating': str(float(avg_rating))
                }
                print uid, 'successfully made booking requests...'

                mix.track(
                    uid, 'request schedule', {
                        'time': dt.datetime.now(),
                        'date': dt.datetime.strftime(date, '%Y%m%d'),
                        'start_time_range_begin': start_time_range_begin,
                        'start_time_range_begin_min':
                        start_time_range_begin_min,
                        'start_time_range_end': start_time_range_end,
                        'start_time_range_end_min': start_time_range_end_min,
                        'taking_time': taking_time,
                        'additional_time': additional_time,
                        'appointment_type': appointment_type,
                        'have_pet': have_pet,
                        'master_gender': master_gender,
                        'isdirty': isdirty,
                        'status': 'find homemaster'
                    })
                mongo_logger.debug('%s made booking requests' % uid,
                                   extra={'user_id': uid})

            self.set_status(Response.RESULT_OK)

        except Exception, e:
            session.rollback()
            add_err_message_to_response(ret, err_dict['err_mysql'])
            self.set_status(Response.RESULT_SERVERERROR)
            print_err_detail(e)
            mongo_logger.error('error occurred when request schedule',
                               extra={'err': str(e)})

            # if error occur, then remove all keys
            holder.remove(store_key)
            for sk in search_keys:
                holder.remove(sk)
Exemple #25
0
    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        ret = {}

        uid = self.get_argument('uid', '')
        search_keys = self.get_argument('search_keys', '')
        store_key = self.get_argument('store_key', '')

        price = self.get_argument('price', 0)
        price_with_task = self.get_argument('price_with_task', 0)

        wage_per_hour = self.get_argument('wage_per_hour', 0)
        address_index = self.get_argument('address_index', 0)

        discounted_price = self.get_argument('discounted_price', 0)
        promotion_code = self.get_argument('promotion_code', '')

        coupon_id = self.get_argument('coupon_id', '')
        coupon_discount_price = self.get_argument('coupon_discount_price', 0)

        laundry_apply_all = self.get_argument(
            'laundry_apply_all', 0)  # -1 - 없앰, 0 - one time, 1 - all time

        user_type = self.get_argument('user_type', 'unknown')

        # convert datetime

        # for ios fix
        if discounted_price != 0:
            discounted_price = discounted_price.replace('Optional(',
                                                        '').replace(')', '')

        price = int(price)
        price_with_task = int(price_with_task)
        discounted_price = int(discounted_price)
        coupon_discount_price = int(coupon_discount_price)
        laundry_apply_all = int(laundry_apply_all)
        wage_per_hour = int(wage_per_hour)

        print 'price_with_task', price_with_task
        print 'discounted_price', discounted_price

        search_keys = search_keys.split(',')

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        try:
            session = Session()
            userdao = UserDAO()
            masterdao = MasterDAO()
            promotiondao = PromotionDAO()
            addressdao = AddressDAO()
            coupondao = CouponDAO()

            holder = IntermediateValueHolder()

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

            obj = holder.retrieve(store_key)
            print obj
            if obj == None:
                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)
                return

            # retrieve all stored values
            uid = obj['user_id']
            mid = obj['master_id']
            dates = obj['dates']
            time = obj['time']
            appointment_type = obj['appointment_type']
            additional_task = obj['additional_task']
            org_additional_task = additional_task

            taking_time = obj['taking_time']
            first_added_time = obj['first_added_time']
            additional_time = obj['additional_time']
            total_time = obj['total_time']
            master_gender = obj['master_gender']
            have_pet = obj['have_pet']
            isdirty = obj['isdirty']

            is_b2b = userdao.is_b2b(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)

            # set tool info
            havetools = 1
            if additional_task >= 64:
                havetools = 0

            card_idx = 0
            addr_idx = 0

            # get card and address idx
            if is_b2b:
                addr_idx = address_index
            else:
                addr_idx = userdao.get_user_default_address_index(uid)

            card_idx = userdao.get_user_default_card_index(uid)

            i = 1
            booking_ids = []
            start_time_list = []

            for date in dates:  #
                print date, time
                booking_id = hashids.encode(int(date + time.replace(':', '')))
                print 'key', booking_id
                master_id = mid

                date = dt.datetime.strptime(date, '%Y%m%d')
                dow = date.date().weekday()
                booking_time = dt.time(hour=int(time.split(':')[0]),
                                       minute=int(time.split(':')[1]))

                start_time = dt.datetime.combine(date, booking_time)
                estimated_end_time = start_time + dt.timedelta(
                    minutes=total_time)
                cleaning_duration = taking_time

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

                else:  # 나머지
                    actual_price = price
                    if havetools == 1:
                        additional_task = 0
                    else:
                        additional_task = 64

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

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

                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,
                    user_type=user_type,
                    wage_per_hour=wage_per_hour,
                    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 is_b2b:
                session.commit()

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

                send_jandi('NEW_BOOKING', '[b2b]새 예약 알림', 'b2b 고객님 예약완료',
                           user_name)

                # b2b용 알림톡 추가 필요

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

                mongo_logger.debug('b2b confirm booking',
                                   extra={
                                       'user_id': uid,
                                       'master_id': mid,
                                       'booking_id': booking_ids[0]
                                   })

                return

            charge_price = price_with_task - (discounted_price +
                                              coupon_discount_price)

            # 1주 1회면서, 이벤트 기간인 경우에는 결제 하지 않음
            import redis
            try:
                from utils.secrets import REDIS_HOST, REDIS_PORT, REDIS_PWD
            except ImportError:
                REDIS_HOST = 'localhost'
                REDIS_PORT = 6379
                REDIS_PWD = ''

            r = redis.Redis(host=REDIS_HOST,
                            port=REDIS_PORT,
                            password=REDIS_PWD)
            event_on = r.get('free_event')

            print event_on
            if appointment_type == 4 and event_on:
                charge_price = price_with_task - price

                # 1회 이벤트 고객임을 명시해야함
                # table 필요
                free_event = UserFreeEvent(booking_request_id=request_id,
                                           user_id=uid,
                                           datetime=dt.datetime.now())
                session.add(free_event)

            if charge_price <= 0:
                ret_code = True
                msg = ''
            else:
                ret_code, msg = request_payment(uid, user_name, booking_ids[0],
                                                charge_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)

                if coupon_id != '':
                    coupondao.set_coupon_status(coupon_id, 1, booking_ids[0],
                                                price_with_task)

                # change status to paid
                try:
                    first_booking = session.query(Booking, User, MasterPushKey) \
                                            .join(User, Booking.user_id == User.id) \
                                            .outerjoin(MasterPushKey, Booking.master_id == MasterPushKey.master_id) \
                                            .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
    def get_available_slots(self,
                            gu_id,
                            geohash,
                            appointment_type,
                            taking_time,
                            prefer_women,
                            have_pet,
                            isdirty,
                            update=False,
                            appointment_date=None,
                            apply_to_all_behind=0,
                            user_id='',
                            master_id='',
                            by_manager=0,
                            request_id=''):
        try:
            available_master_schedules_dict = {}

            #print gu_id, type(gu_id)
            #if gu_id == 2122010 or gu_id == 2157010 or gu_id == 2158050 or gu_id == 2152020: # 은평구, 강서구, 구로구 막기
            #    return {}

            available_start_date = 1
            available_end_date = HMScheduler.DAYS_OF_WEEK * 3 - 1  # 3 weeks ahead
            all_end_date = HMScheduler.DAYS_OF_WEEK * 11  # 2 months

            start_date = dt.datetime.now()

            if update == True:
                if appointment_type in [
                        BC.ONE_TIME_A_MONTH, BC.TWO_TIME_A_MONTH,
                        BC.FOUR_TIME_A_MONTH
                ]:
                    start_date = appointment_date

                    available_start_date = -1 * HMScheduler.DAYS_OF_WEEK * (
                        4 / appointment_type) + 1
                    available_end_date = HMScheduler.DAYS_OF_WEEK * (
                        4 / appointment_type * 2) - 2
                    all_end_date = HMScheduler.DAYS_OF_WEEK * (
                        (4 / appointment_type) + 8) - 1
                else:
                    available_start_date = 1
                    if by_manager == 1:  # manager가 변경한 경우
                        available_start_date = 0
                    available_end_date = HMScheduler.DAYS_OF_WEEK * 3 - 1  # 3 weeks ahead
                    all_end_date = HMScheduler.DAYS_OF_WEEK * 11  # 2 months

            tomorrow = start_date + dt.timedelta(days=available_start_date)
            tomorrow = tomorrow.date()

            cur_date = tomorrow
            max_date = tomorrow + dt.timedelta(
                days=available_end_date)  # 3 weeks ahead

            tomorrow_key = dt.datetime.strftime(tomorrow, '%Y%m%d')
            max_date_key = dt.datetime.strftime(max_date, '%Y%m%d')

            print 'date_keys'
            print tomorrow_key, max_date_key

            occupied_slots = self.get_occupied_slots(
                gu_id, cur_date, cur_date + dt.timedelta(days=all_end_date),
                prefer_women, have_pet, master_id, request_id)

            if isdirty == True and not appointment_type in [
                    BC.ONE_TIME_A_MONTH, BC.TWO_TIME_A_MONTH,
                    BC.FOUR_TIME_A_MONTH
            ]:
                taking_time += 120  # if it is dirty then add two hours

            # find any free slots based on hours required for cleaning for 10 weeks
            while cur_date <= tomorrow + dt.timedelta(
                    days=all_end_date):  # 11 weeks
                daily_available_schedule_dict = self.get_available_slots_for_day(
                    geohash, cur_date, taking_time, occupied_slots, isdirty,
                    by_manager)
                available_master_schedules_dict[self.date_to_str(
                    cur_date)] = daily_available_schedule_dict

                cur_date += dt.timedelta(days=1)

            available_master_schedules_dict = collections.OrderedDict(
                sorted(available_master_schedules_dict.items(),
                       key=lambda x: x[0]))

            print 'appointment_type', appointment_type

            # if update only one schedule, then don't have to check rest of the schedules
            if update == True and apply_to_all_behind == 0:
                appointment_type = 0

            # if appointment_type > 0, then we should find out days that would be free for number of iteration
            if appointment_type in [
                    BC.ONE_TIME_A_MONTH, BC.TWO_TIME_A_MONTH,
                    BC.FOUR_TIME_A_MONTH
            ]:
                for day in available_master_schedules_dict:  # each day
                    if day > max_date_key: break

                    for master_id in available_master_schedules_dict[
                            day]:  # each master
                        iter_available_times = []
                        iter_available_times.append(
                            available_master_schedules_dict[day][master_id])

                        iter_count = self.count_of_iteration(appointment_type)

                        for i in xrange(iter_count - 1):
                            next_date = dt.datetime.strptime(
                                day, '%Y%m%d') + dt.timedelta(
                                    weeks=(4 / appointment_type) * (i + 1))
                            next_date = dt.datetime.strftime(
                                next_date, '%Y%m%d')

                            if next_date in available_master_schedules_dict:
                                if master_id in available_master_schedules_dict[
                                        next_date]:
                                    iter_available_times.append(
                                        available_master_schedules_dict[
                                            next_date][master_id])

                        reduced = func.reduce(np.intersect1d,
                                              iter_available_times)
                        new_available_times = reduced
                        if not isinstance(reduced,
                                          list):  # sometimes it returns list
                            new_available_times = reduced.tolist()
                        available_master_schedules_dict[day][
                            master_id] = new_available_times

            # filter by duration (two weeks ahead from tomorrow)
            available_master_schedules_dict = dict(
                (key, value)
                for key, value in available_master_schedules_dict.iteritems()
                if tomorrow_key <= key <= max_date_key)

            masterdao = MasterDAO()
            userdao = UserDAO()
            blocked_masters = userdao.get_blocked_masters(user_id)

            print 'blocked masters'
            print blocked_masters

            master_rating_dict = {}
            # rebuild dictionary by time value
            for day in available_master_schedules_dict:
                day_schedule_dict = available_master_schedules_dict[day]

                # convert master_id key to time key
                new_schedule_dict = {}
                for master_id in day_schedule_dict:
                    if master_id in blocked_masters:
                        continue

                    available_times = day_schedule_dict[master_id]
                    available_times_num = len(available_times)

                    if not master_id in master_rating_dict:
                        avg_rating = masterdao.get_avg_master_cleaning_rating(
                            master_id)
                        master_rating_dict[master_id] = avg_rating

                    for time in available_times:
                        #time = self.time_to_str(time) # convert nptime to string
                        #score_criteria = (master_id, (1.0 / available_times_num), master_rating_dict[master_id])
                        score_criteria = (master_id, 1,
                                          master_rating_dict[master_id])

                        if not time in new_schedule_dict:
                            new_schedule_dict[time] = []
                            new_schedule_dict[time].append(score_criteria)
                        else:
                            new_schedule_dict[time].append(score_criteria)

                # sort by scoring criteria
                for time in new_schedule_dict:
                    scored_master_ids = [
                        item[0]
                        for item in sorted(new_schedule_dict[time],
                                           key=operator.itemgetter(1, 2),
                                           reverse=True)
                    ]
                    new_schedule_dict[time] = ','.join(scored_master_ids)
                    #new_schedule_dict[time] = sorted(new_schedule_dict[time], key = operator.itemgetter(1, 2), reverse = True)

                new_schedule_dict = collections.OrderedDict(
                    sorted(new_schedule_dict.items(),
                           key=lambda x: x[0]))  # sort by time key

                #available_master_schedules_dict[day]['by_master']   = day_schedule_dict
                available_master_schedules_dict[day][
                    'by_time'] = new_schedule_dict
                available_master_schedules_dict[day][
                    'time_list'] = new_schedule_dict.keys()

            ret_dict = {}

            for day in available_master_schedules_dict:
                day_schedule_dict = available_master_schedules_dict[day]

                if len(day_schedule_dict['time_list']) > 0:  # 가능한 날짜만 보냄.
                    ret_dict[day] = {}
                    ret_dict[day]['by_time'] = day_schedule_dict['by_time']
                    ret_dict[day]['time_list'] = day_schedule_dict['time_list']

            ret_dict = collections.OrderedDict(
                sorted(ret_dict.items(),
                       key=lambda x: x[0]))  # sort by date key

            return ret_dict

        except Exception, e:
            print_err_detail(e)
            return {}
    def post(self):
            self.set_header("Content-Type", "application/json")

            ret = {}

            uid                     = self.get_argument('uid', '')
            search_keys             = self.get_argument('search_keys', '')
            store_key               = self.get_argument('store_key', '')
            
            price                   = self.get_argument('price', 0)
            price_with_task         = self.get_argument('price_with_task', 0)
            discounted_price        = self.get_argument('discounted_price', 0)
            promotion_code          = self.get_argument('promotion_code', '')
            
            laundry_apply_all       = self.get_argument('laundry_apply_all', 0) # -1 - 없앰, 0 - one time, 1 - all time

            # convert datetime
            price                   = int(price)
            price_with_task         = int(price_with_task)
            discounted_price        = int(discounted_price)
            laundry_apply_all       = int(laundry_apply_all)

            search_keys = search_keys.split(',')

            mongo_logger = get_mongo_logger()
            mix = get_mixpanel()

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

                holder = IntermediateValueHolder()

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

                obj = holder.retrieve(store_key)
                print obj
                if obj == None:
                    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)
                    return  

                # retrieve all stored values
                uid                 = obj['user_id']
                mid                 = obj['master_id']
                dates               = obj['dates']
                time                = obj['time']
                appointment_type    = obj['appointment_type']
                additional_task     = obj['additional_task']

                taking_time         = obj['taking_time']
                first_added_time    = obj['first_added_time']
                additional_time     = obj['additional_time']
                total_time          = obj['total_time']
                master_gender       = obj['master_gender']
                have_pet            = obj['have_pet']
                isdirty             = obj['isdirty']

                # 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)

                # set tool info
                havetools = 1
                if additional_task >= 64:
                    havetools = 0

                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)

                i = 1
                booking_ids = []
                start_time_list = []

                for date in dates: # 
                    print date, time
                    booking_id = hashids.encode(int(date + time.replace(':', '')))
                    print 'key', booking_id
                    master_id  = mid

                    date               = dt.datetime.strptime(date, '%Y%m%d')
                    dow                = date.date().weekday()
                    booking_time       = dt.time(hour = int(time.split(':')[0]), minute = int(time.split(':')[1]))

                    start_time         = dt.datetime.combine(date, booking_time)
                    estimated_end_time = start_time + dt.timedelta(minutes = total_time)
                    cleaning_duration  = taking_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

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

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

                    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 = True
                    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)
                    
                    session.commit()

                    mix.track(uid, 'confirm booking', {'time' : dt.datetime.now(), 'appointment_type' : appointment_type, 'additional_task' : additional_task})
                    mongo_logger.debug('confirm booking', extra = {'user_id' : uid, 'master_id' : mid, 'booking_id' : booking_ids[0], 'start_time' : start_time_list[0]})

                    #ret['response'] = {'booking_ids' : booking_ids} # victor 요청으로 첫번째 
                    ret['response'] = booking_ids[0]
                    self.set_status(Response.RESULT_OK)

                    # notification to managers
                    send_booking_iphone(booking_ids[0])

                    appointment_type_text = ''
                    if appointment_type == BC.ONE_TIME or appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                        appointment_type_text = '1회'
                    elif appointment_type == BC.FOUR_TIME_A_MONTH:
                        appointment_type_text = '매주'
                    elif appointment_type == BC.TWO_TIME_A_MONTH:
                        appointment_type_text = '2주 1회'
                    elif appointment_type == BC.ONE_TIME_A_MONTH:
                        appointment_type_text = '4주 1회'

                    master_phone = masterdao.get_master_phone(mid)
                    send_alimtalk(master_phone, 'noti_manager_new', user_name, appointment_type_text)

                    try:
                        first_booking = session.query(Booking, User, MasterPushKey) \
                                                .join(User, Booking.user_id == User.id) \
                                                .outerjoin(MasterPushKey, Booking.master_id == MasterPushKey.master_id) \
                                                .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  
Exemple #28
0
class ChangeCircleHandler(tornado.web.RequestHandler):
    def post(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

        print "call change_circle_handler"

        ret = {}

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

        new_booking_date = self.get_argument(
            'date', dt.datetime.strftime(dt.datetime.now(), '%Y%m%d'))
        new_booking_time = self.get_argument('time', '08:00')
        master_ids = self.get_argument('master_ids', [])
        new_appointment_type = self.get_argument('appointment_type', '')

        # convert parameters
        selected_date_str = new_booking_date
        time_str = new_booking_time
        new_booking_date = dt.datetime.strptime(new_booking_date, '%Y%m%d')
        master_ids = master_ids.split(',')
        new_appointment_type = int(new_appointment_type)

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

        print 'change circle'
        print selected_date_str, time_str
        print '*' * 100

        try:
            session = Session()
            try:
                row = session.query(Booking).filter(
                    Booking.id == org_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

            org_request_id = row.request_id
            org_appointment_index = row.appointment_index
            org_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
            user_id = row.user_id
            card_idx = row.card_idx
            addr_idx = row.addr_idx
            havetools = row.havetools
            have_pet = row.havepet
            isdirty = row.is_dirty
            master_gender = row.master_gender
            cleaning_duration = row.cleaning_duration
            #payment_status          = BC.BOOKING_UNPAID_YET

            # 원래 예약된 정보 불러오기
            all_bookings = session.query(Booking) \
                                  .filter(Booking.request_id == org_request_id) \
                                  .filter(Booking.appointment_index >= org_appointment_index) \
                                  .filter(Booking.cleaning_status > BC.BOOKING_CANCELED) \
                                  .order_by(Booking.start_time) \
                                  .all()
            # 예약된 정보의 상태 변경
            for booking in all_bookings:
                print "change cleanning_status"
                booking.cleaning_status = BC.BOOKING_CANCELED
                # 결제 상태에 따른 상태 변경
            session.commit()

            # 주기에 따른 예약 생성
            # request id to group each individual bookings
            request_id = str(uuid.uuid4())
            # 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 + user_id)

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

            cal_appointment_type = new_appointment_type
            count_of_iteration = cal_appointment_type * 2 + 1  # 2 months

            date_list = []

            week_const = 4 / cal_appointment_type

            for i in xrange(count_of_iteration):
                date = new_booking_date + dt.timedelta(weeks=week_const * i)
                date = dt.datetime.strftime(date, '%Y%m%d')
                date_list.append(date)

            print "date_list : ", date_list

            master_num = len(master_ids)

            i = 0
            booking_info = {}
            time = new_booking_time

            house_type, size = userdao.get_user_house_type_size(org_booking_id)
            print "house_type : ", house_type
            print "size : ", size

            while i < master_num:
                mid = master_ids[i]
                master_date_keys = []

                name, img_url, avg_rating = masterdao.get_master_name_img_and_average_rating(
                    mid)

                print "master_name : ", name
                print "img_url : ", img_url
                print "avg_rating : ", avg_rating

                for date in date_list:
                    key = '%s_%s' % (mid, date)
                    master_date_keys.append(key)

                print "master_date_keys : ", master_date_keys

                booking_item_key = '%s_%s_%d' % (user_id, master_date_keys[0],
                                                 new_appointment_type)
                #if holder.store_keys(master_date_keys) and not masterdao.is_master_off_date(mid, new_booking_date.date()): # 메모리에 키가 하나도 없을 때, 즉 예약이 가능할 때
                #    holder.store(booking_item_key, booking_info)

                new_appointment_idx = 1

                for date in date_list:
                    print date, time
                    booking_id = hashids.encode(
                        int(date + time.replace(':', '')))
                    print 'new_booking_id : ', booking_id
                    date = dt.datetime.strptime(date, '%Y%m%d')
                    dow = date.date().weekday()
                    booking_time = dt.time(hour=int(time.split(':')[0]),
                                           minute=int(time.split(':')[1]))
                    start_time = dt.datetime.combine(date, booking_time)
                    estimated_end_time = start_time  # + dt.timedelta(minute = )
                    print "booking_time : ", booking_time
                    print "start_time : ", start_time
                    print "estimated_end_time : ", estimated_end_time
                i += 1
            '''while i < master_num:
                mid = master_ids[i]
                master_date_keys = []

                name, img_url, avg_rating = masterdao.get_master_name_img_and_average_rating(mid)

                for date in date_list:
                    key = '%s_%s' % (mid, date)
                    master_date_keys.append(key)

                booking_item_key = '%s_%s_%d' % (uid, 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)

                    new_appointment_idx = 1;
                    for date in date_list:
                        print date, time
                        booking_id = hashids.encode(int(date + time.replace(':', '')))
                        dow        = date.date().weekday()

                        print 'key', booking_id
                        booking_time       = dt.time(hour = int(time.split(':')[0]), minute = int(time.split(':')[1]))
                        start_time         = dt.datetime.combine(date, booking_time)
                        estimated_end_time = estimated_end_time - dt.timedelta(minutes = additional_time + first_added_time)

                        booking = Booking(id = booking_id,
                                          request_id = request_id,
                                          user_id = uid,
                                          master_id = mid,
                                          appointment_type = new_appointment_type,
                                          appointment_index = new_appointment_idx,
                                          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)

                    #booking_info['search_keys'] = master_date_keys
                    #booking_info['store_key']   = booking_item_key
                    return
                i += 1'''

            ret['response'] = Response.SUCCESS
            self.set_status(Response.RESULT_OK)
Exemple #29
0
    def post(self):
        self.set_header("Content-Type", "application/json")

        uid = self.get_argument('uid', '')
        taking_time = self.get_argument('taking_time', 25)
        additional_time = self.get_argument('additional_time', 10)
        appointment_type = self.get_argument('appointment_type', 0)
        have_pet = self.get_argument('have_pet', 0)
        master_gender = self.get_argument('master_gender', 0)
        isdirty = self.get_argument('isdirty', 0)

        # convert
        appointment_type = int(appointment_type)
        have_pet = int(have_pet)

        taking_time = int(taking_time)
        additional_time = int(additional_time)
        taking_time_in_minutes = taking_time * 6
        additional_time_in_minutes = additional_time * 6
        total_taking_time_in_minutes = taking_time_in_minutes + additional_time_in_minutes

        master_gender = int(master_gender)  # 0 dont care 1 women 2 men
        isdirty = int(isdirty)

        ret = {}

        print 'recommend schedule'
        print 'taking time :', taking_time_in_minutes

        mongo_logger = get_mongo_logger()

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

        mix = get_mixpanel()

        try:
            session = Session()

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

            holder = IntermediateValueHolder()

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

            # get user's address and cover address to gu code
            address, geohash5, geohash6 = userdao.get_user_address(uid)
            gu_id = addrdao.get_gu_id(address)

            start_time_range_begin = 8
            start_time_range_end = 18

            # 똥집인 경우 3시간 추가됨.
            if isdirty == 1:
                if appointment_type == BC.ONE_TIME or appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                    total_taking_time_in_minutes += 120

            #get available homemaster's time table day by day
            schedule_by_date_list = masterdao.get_recommended_schedule(
                gu_id, have_pet, master_gender, appointment_type, geohash6,
                dt.datetime.now().date())
            success, msg, store_key, search_keys, result = masterdao.find_master_by_score(schedule_by_date_list, \
                                                gu_id, \
                                                uid, \
                                                appointment_type, \
                                                None, \
                                                start_time_range_begin, \
                                                0,
                                                start_time_range_end, \
                                                0,
                                                total_taking_time_in_minutes, \
                                                geohash6,
                                                True)

            # if not successful
            if success != 'SUCCESS':
                print 'haha no recommendation.....'
                self.set_status(Response.RESULT_OK)
                ret['response'] = 'NoRecommendation'
                mongo_logger.error('have no recommendation',
                                   extra={'err': msg})
                #add_err_message_to_response(ret, err_dict['err_hm_no_recommendation'])
                #self.write(json.dumps(ret))
                return
            else:
                schedules = []

                for row in result:
                    s = {}
                    s['date'] = row['date']
                    s['start_time'] = time_to_str(row['start_time'])
                    s['end_time'] = time_to_str(row['end_time'])

                    schedules.append(s)

                # 스케쥴이 이미 해당 날짜에 있다면, 있다고 표시하고 리턴함
                num_schedules_on_dates = userdao.get_user_schedule_on_dates(
                    uid, [
                        dt.datetime.strptime(str(s['date']), '%Y%m%d').date()
                        for s in schedules
                    ])
                if num_schedules_on_dates > 0:
                    print 'already have appointment on that days, no recommendation.....'

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

                    self.set_status(Response.RESULT_OK)
                    ret['response'] = 'NoRecommendation'
                    mongo_logger.error(
                        'have no recommendation',
                        extra={'err': 'already have cleaning on that day'})
                    #add_err_message_to_response(ret, err_dict['err_hm_no_recommendation'])
                    #self.write(json.dumps(ret))
                    return

                mid = row['mid']
                name, img_url, avg_rating = masterdao.get_master_name_img_and_average_rating(
                    mid)

                search_keys_str = ','.join(search_keys)
                print 'search key string :', search_keys_str
                ret['response'] = {
                    'store_key': store_key,
                    'search_keys': search_keys_str,
                    'schedules': schedules,
                    'uid': uid,
                    'mid': row['mid'],
                    'name': name,
                    'img_url': img_url,
                    'avg_rating': str(float(avg_rating))
                }

                mix.track(uid, 'recommend', {
                    'time': dt.datetime.now(),
                    'master_gender': master_gender
                })
                mongo_logger.debug('%s got recommendation' % uid,
                                   extra={'user_id': uid})

                self.set_status(Response.RESULT_OK)

                print uid, 'got recommendation '

                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'])
            mongo_logger.error('error occurred when make recommendation',
                               extra={'err': str(e)})

            # if error occur, then remove all keys
            holder.remove(store_key)
            for sk in search_keys:
                holder.remove(sk)
Exemple #30
0
    def get(self):
        self.set_header("Content-Type", "application/json")
        self.set_header('Access-Control-Allow-Origin', '*')

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

        ret = {}

        try:
            # retrieve update logs from mongo
            '''{ "_id" : ObjectId("574436f28a34832173d79a74"),
            "timestamp" : Timestamp(1464088306, 392),
            "module" : "update_schedule_handler",
            "fileName" : "/home/dev/webapps/src/rest/booking/update_schedule_handler.py",
            "apply_to_all_behind" : 0,
             "lineNumber" : 181,
             "message" : "update logs",
             "user_id" : "cef0e0ef-b6b9-44c1-bd99-f59a844e51e1",
             "org_time" : "2016년 06월 17일 금요일 오전 11시",
             "thread" : NumberLong("140546989348672"),
             "level" : "DEBUG",
             "threadName" : "MainThread",
             "loggerName" : "hm_logger",
             "org_master_id" : "bd1bae4b-3b1b-41e1-8c23-703226457a19",
             "booking_id" : "GdB6wdQJ37m8LgkD",
             "changed_master_id" : "d0060b43-d1e4-4b48-aa53-b6817913275d",
             "changed_time" : "2016년 06월 19일 일요일 오전 11시",
             "method" : "post" }'''
            masterdao = MasterDAO()

            update_records = []
            cursor = self.db.find({
                'message': 'update logs',
                'booking_id': booking_id
            }).sort('timestamp', 1)

            for item in cursor:
                org_master_id = item['org_master_id']
                changed_master_id = item['changed_master_id']

                org_master_name = masterdao.get_master_name(org_master_id)
                changed_master_name = masterdao.get_master_name(
                    changed_master_id)

                locale_time = item['timestamp'].as_datetime() + dt.timedelta(
                    hours=9)

                logging_time = convert_datetime_format2(locale_time)

                by_whom = '없음'
                if 'by_manager' in item:
                    if item['by_manager'] == 1:
                        by_whom = '매니저'
                    else:
                        by_whom = '고객'

                org_time = item['org_time'] if 'org_time' in item else ''
                changed_time = item[
                    'changed_time'] if 'changed_time' in item else ''

                update_records.append({
                    'org_time': org_time,
                    'changed_time': changed_time,
                    'org_master_name': org_master_name,
                    'changed_master_name': changed_master_name,
                    'logging_time': logging_time,
                    'by_whom': by_whom
                })

            ret['response'] = {'update_records': update_records}
            self.set_status(Response.RESULT_OK)

        except Exception, e:
            print_err_detail(e)
            self.set_status(Response.RESULT_SERVERERROR)
            add_err_message_to_response(ret, err_dict['err_mysql'])