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)
示例#2
0
        except NoResultFound, e:
                session.close()
                return False               

        except MultipleResultsFound, e:
            session.close()
            return False

        userdao = UserDAO()
        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))
        date                = str(convert_datetime_format(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     = str(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)

        # notify homemaster about appointment
        sms_sender = SMS_Sender()
        text = BOOKING_CONFIRM_TEXT % (master_name, user_name, date, address, appointment_type, additional_task, take_time_str, message, trash_location)
        sms_sender.send(sender = MAIN_CALL, mtype = 'lms', to = master_phone, subject = BOOKING_TEXT_SUBJECT, text = text)
    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 get_mybookings(self, session, user_id, mode):
        bookings = []

        now = dt.datetime.now()

        bookingdao = BookingDAO()

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

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

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

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

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

                        bookings.append(booking)

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

                print now.date()

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

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

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

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

                        bookings.append(booking)

        except Exception, e:
            print_err_detail(e)
            raise Exception(e)
class MyBookingsDetailHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header("Content-Type", "application/json")

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

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

        try:
            booking_detail = {}
            session = Session()

            print booking_id

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

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

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

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

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

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

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

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

            discount_price = 0

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

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

            booking_detail['coupon_discount_price']  = discount_price

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


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

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


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

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

            user_id = row.Booking.user_id

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

            print booking_id, 'successfully retrieved...by', user_id
    def post(self):
        self.set_header("Content-Type", "application/json")
        booking_id = self.get_argument('booking_id', '')
        reason_id = self.get_argument('reason_id', 0)
        etc_reason = self.get_argument('etc_reason', '')
        charge_amount = self.get_argument('charge_amount', 0)

        charge_amount = int(charge_amount)
        reason_id = int(reason_id)

        print 'cancel all charge amount : ', charge_amount

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

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

            stmt = session.query(Booking.request_id).filter(
                Booking.id == booking_id).subquery()
            first_startime = session.query(Booking.start_time).filter(
                Booking.request_id == stmt).order_by(
                    Booking.start_time).first()[0]

            result = 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.request_id == stmt) \
                         .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED)) \
                         .all()

            # 서비스를 처음 이용한지 2달이 넘었는지 아닌지 조사,
            # 넘지 않았다면 이미 부과된 금액에 대해서도 1회 서비스 금액 과의 차액만큼 부과됨
            current_time = dt.datetime.now()

            completed_charge = 1
            if current_time >= first_startime + dt.timedelta(days=57):
                completed_charge = 0

            cancel_all_charge = 0
            # 그동안의 모든 예약에 대해서 처리함
            for row in result:
                charge = 0

                new_status = BC.BOOKING_CANCELED_CHARGE

                bid = row.Booking.id
                user_id = row.Booking.user_id
                appointment_time = row.Booking.start_time
                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

                diff_in_hours = (appointment_time -
                                 current_time).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

                # 이미 지불한 금액에 대해 1회 비용의 차액만큼 계산
                if completed_charge == 1:
                    if current_cleaning_status == BC.BOOKING_COMPLETED:
                        # 차액만큼 계속 더함
                        cancel_all_charge += charge_amount

                if current_payment_status == BC.BOOKING_PAID and current_cleaning_status == BC.BOOKING_UPCOMMING:
                    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, bid, 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   = current_time
                row.Booking.charging_price = int(charge)
                row.Booking.status = new_status
                row.Booking.cleaning_status = BC.BOOKING_CANCELED
                row.Booking.payment_status = new_status

                # add cancel reason
                CANCEL_ALL = 1
                reason = session.query(CancelReason).filter(
                    CancelReason.booking_id == bid)
                if reason.count() == 0:
                    cancel_reason = CancelReason(booking_id=bid,
                                                 user_id=user_id,
                                                 reason_id=reason_id,
                                                 etc_reason=etc_reason,
                                                 kind=CANCEL_ALL,
                                                 cancel_time=dt.datetime.now())
                    session.add(cancel_reason)
                else:
                    reason_row = reason.one()
                    reason_row.kind = 1
            '''if cancel_all_charge > 0:
                user_name = userdao.get_user_name(user_id)
                ret_code, msg = request_charge(user_id, user_name, cancel_all_charge)
                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  '''

            key = userdao.get_user_salt_by_id(row.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 = str(row.Booking.appointment_type)

            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_ALL_TEXT % (appointment_type, username, userphone, master_name, date)
            #send_result = 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_all',
                              username, date, appointment_type_text)

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

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

            session.commit()

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

            ret['response'] = Response.SUCCESS
            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', '')
        charge_amount = self.get_argument('charge_amount', 0)
        no_fee = self.get_argument('no_fee', 0)

        regular_cancel_charge = self.get_argument('regular_cancel_charge', 0)

        charge_amount = int(charge_amount)
        reason_id = int(reason_id)
        no_fee = int(no_fee)

        regular_cancel_charge = int(regular_cancel_charge)

        print 'cancel all charge amount : ', charge_amount
        print 'reason_id : ', reason_id
        print 'etc_reason : ', etc_reason

        ret = {}

        mongo_logger = get_mongo_logger()
        mix = get_mixpanel()

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

            stmt = session.query(Booking.request_id).filter(
                Booking.id == booking_id).subquery()
            first_startime = session.query(Booking.start_time).filter(
                Booking.request_id == stmt).order_by(
                    Booking.start_time).first()[0]

            result = 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.request_id == stmt) \
                         .filter(or_(Booking.cleaning_status == BC.BOOKING_UPCOMMING, Booking.cleaning_status == BC.BOOKING_STARTED, Booking.cleaning_status == BC.BOOKING_COMPLETED)) \
                         .all()

            # 서비스를 처음 이용한지 2달이 넘었는지 아닌지 조사,
            # 넘지 않았다면 이미 부과된 금액에 대해서도 1회 서비스 금액 과의 차액만큼 부과됨
            current_time = dt.datetime.now()

            completed_charge = 1
            if current_time >= first_startime + dt.timedelta(days=57):
                completed_charge = 0

            cancel_all_charge = 0
            # 그동안의 모든 예약에 대해서 처리함
            for row in result:
                charge = 0

                new_status = BC.BOOKING_CANCELED_CHARGE

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

                username = str(crypto.decodeAES(row.User.name))

                request_id = row.Booking.request_id
                appointment_index = row.Booking.appointment_index

                bid = row.Booking.id
                user_id = row.Booking.user_id
                appointment_time = row.Booking.start_time
                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
                appointment_type = row.Booking.appointment_type

                diff_in_hours = (appointment_time -
                                 current_time).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

                # 이미 지불한 금액에 대해 1회 비용의 차액만큼 계산
                if completed_charge == 1:
                    if current_cleaning_status == BC.BOOKING_COMPLETED:
                        # 차액만큼 계속 더함
                        _, house_size, house_type = userdao.get_user_address_detail_by_index(
                            user_id, row.Booking.addr_idx)
                        time_prices = get_basic_time_price(
                            house_type, house_size)
                        try:
                            print time_prices[0]['price']
                            print time_prices[appointment_type]['price']
                            charge_amount = int(
                                time_prices[0]['price'] -
                                time_prices[appointment_type]['price'])
                        except Exception:
                            charge_amount = 3000
                        cancel_all_charge += charge_amount

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

                is_event = True if is_event != None else False

                if is_event == True and appointment_index == 1:
                    partial = '0'
                    cancel_amount = row.Booking.price_with_task - row.Booking.price
                    cancel_payment(user_id, bid, cancel_amount, partial)

                    # 취소에 대한 결제 필요
                    # 8회 이상 썼다면(완료카운트 9회 미만일 경우 결제)
                    complete_count = session.query(Booking) \
                            .filter(Booking.request_id == request_id) \
                            .filter(Booking.cleaning_status == 2) \
                            .count()

                    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

                if current_payment_status == BC.BOOKING_PAID and current_cleaning_status == BC.BOOKING_UPCOMMING:
                    if no_fee == 1:
                        charge = 0

                    new_status = BC.BOOKING_CANCELED_REFUND

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

                    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, bid, 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

                elif current_payment_status == BC.BOOKING_UNPAID_YET and current_cleaning_status == BC.BOOKING_UPCOMMING:
                    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, bid, charging_price,
                            appointment_type)
                        if ret_code == False:
                            new_status = BC.BOOKING_PAYMENT_FAILED

                #row.Booking.modified_date   = current_time
                if current_cleaning_status == BC.BOOKING_UPCOMMING:
                    row.Booking.charging_price = int(charge)
                    row.Booking.status = new_status
                    row.Booking.cleaning_status = BC.BOOKING_CANCELED
                    row.Booking.payment_status = new_status

                # add cancel reason
                CANCEL_ALL = 1
                reason = session.query(CancelReason).filter(
                    CancelReason.booking_id == bid)
                if reason.count() == 0:
                    cancel_reason = CancelReason(booking_id=bid,
                                                 user_id=user_id,
                                                 reason_id=reason_id,
                                                 etc_reason=etc_reason,
                                                 kind=CANCEL_ALL,
                                                 cancel_time=dt.datetime.now())
                    session.add(cancel_reason)
                else:
                    try:
                        reason_row = reason.one()
                        reason_row.kind = 1
                    except Exception, e:
                        print e

            # 수수료 임시 처리 막기
            #cancel_all_charge = 0
            if cancel_all_charge > 0 and source == 'hm' and regular_cancel_charge == 0:
                user_name = userdao.get_user_name(user_id)
                ret_code, msg = request_charge(user_id, user_name,
                                               cancel_all_charge)
                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

            if row != None:
                key = userdao.get_user_salt_by_id(row.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 = str(row.Booking.appointment_type)

                print 'app _type'
                print appointment_type

                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_ALL_TEXT % (appointment_type, username, userphone, master_name, date)
                #send_result = 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_all', username, date, appointment_type_text)

                cancel_all_reasons = []
                cancel_all_reasons.append('너무 비싸요')
                cancel_all_reasons.append('제가 여행을 가요')
                cancel_all_reasons.append('청소품질이 마음에 들지 않아요')
                cancel_all_reasons.append('필요할 때에만 서비스를 이용하고 싶어요')
                cancel_all_reasons.append('다른 업체로 바꿀래요')
                cancel_all_reasons.append('원하던 홈마스터가 오질 않아요')
                cancel_all_reasons.append('저 이사가요')
                cancel_all_reasons.append('기타')
                cancel_all_reasons.append('관리자가 취소 했습니다')

                cancel_reason = cancel_all_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 all...'

                master_pushkey = masterdao.get_master_pushkey(master_id)
                send_all_bookings_canceled('android', [master_pushkey],
                                           booking_id, date, username)

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

                user_name = userdao.get_user_name(user_id)

                content = '''{} 홈마스터님
정기 고객의 예약이 전체 취소 되었습니다.

고객 : {}
주기 : {}'''.format(master_name, user_name, appointment_type_text)

                print 'text'
                print appointment_type_text
                message_sender = MessageSender()
                message_sender.send([master_phone], '예약 전체 취소 알림', content)

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

            coupondao = CouponDAO()
            coupondao.cancelall_coupon_usage(booking_id)

            session.commit()

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

            ret['response'] = Response.SUCCESS
            self.set_status(Response.RESULT_OK)
示例#8
0
    def get_mybookings(self, session, user_id, mode):
        bookings = []

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

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

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

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

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

                        bookings.append(booking)

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

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

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

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

                        bookings.append(booking)
示例#9
0
                        #if row.Booking.appointment_type == BC.ONE_TIME or row.Booking.appointment_type == BC.ONE_TIME_BUT_CONSIDERING:
                        #    if row.Booking.is_dirty == 1:
                        #        tooktime -= 120

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

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

                        bookings.append(booking)

        except Exception, e:
            print_err_detail(e)
            raise Exception(e)

        return bookings

    def get(self, **params):