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
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
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'])
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'])
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'])
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'])
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'])
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)
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
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)
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)
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'])