/
tasks.py
349 lines (305 loc) · 11.3 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
from __future__ import absolute_import
import datetime
import logging
from django.conf import settings
from django.utils import timezone
# from django.utils import timezone
from django.db.models import F
import jpush
from celery import shared_task
from .models import TimeSlot, TimeSlotAttendance,\
Order, Teacher, Coupon, Evaluation, School, LiveCourseTimeSlot,\
ExerciseSubmit
from .utils.klx_api import klx_reg_student, klx_reg_teacher, klx_relation
from .utils.smsUtil import tpl_send_sms, TPL_STU_REMIND_COURSE
logger = logging.getLogger('tasks')
class Remind:
# 通知和提醒类型
COURSE_CHANGED = "1"
ORDER_REFUNDED = "2"
COURSE_CONFIRMED = "3"
COURSE_REMIND = "4"
COUPON_WILL_EXPIRED = "5"
EVALUATION_SCHEDULED = "6"
EXERCISE_MISTAKES = "7"
# 标题
titles = {
COURSE_CHANGED: '课程变动',
ORDER_REFUNDED: '退费成功',
COURSE_CONFIRMED: '完课评价',
COURSE_REMIND: '课前通知',
COUPON_WILL_EXPIRED: '奖学金即将到期',
EVALUATION_SCHEDULED: '测评建档',
EXERCISE_MISTAKES: '错题本更新啦',
}
@staticmethod
def title(remind_type):
return Remind.titles.get(remind_type)
@shared_task
def autoConfirmClasses():
operateTargets = TimeSlot.should_auto_confirmed_objects.all()
logger.debug("[autoConfirmClasses] target amount:%d" %(len(operateTargets)))
user_ids = []
for timeslot in operateTargets:
timeslot.confirm()
logger.debug("[autoConfirmClasses] The Timeslot ends at %s ,was been set the attendance to %s" %(timeslot.end, timeslot.attendance))
user_ids.append(timeslot.order.parent.user_id)
# JPush 通知
extras = {
"type": Remind.COURSE_CONFIRMED, # 完课评价
"code": None
}
send_push.delay(
"您有课程已完成,去评价>>",
title=Remind.title(Remind.COURSE_CONFIRMED),
user_ids=user_ids,
extras=extras
)
return True
@shared_task
def autoNotifyComment():
operateTargets = TimeSlot.auto_notify_comment_objects.all()
logger.debug("[autoNotifyComment] target amount:%d" % (len(operateTargets)))
# JPush 通知
extras = {
"type": Remind.COURSE_CONFIRMED, # 完课评价
"code": None
}
for timeslot in operateTargets:
logger.debug("[autoNotifyComment] The Timeslot ends at %s" % (timeslot.end))
teacher_name = timeslot.main_teacher.name
send_push.delay(
"%s 老师的课上完了,觉得怎么样呢,去评价发表你的看法吧>>" % teacher_name,
title=Remind.title(Remind.COURSE_CONFIRMED),
user_ids=[timeslot.order.parent.user_id],
extras=extras
)
attendance = TimeSlotAttendance.objects.create(record_type='a')
timeslot.attendance = attendance
timeslot.save()
return True
@shared_task
def autoRemindClasses():
# JPush 通知
extras = {
"type": Remind.COURSE_REMIND, # 课前通知
"code": None
}
remind_time = timezone.now() + TimeSlot.REMIND_TIME
timeslots = TimeSlot.objects.filter(
deleted=False,
start__lt=remind_time,
end__gt=timezone.now(), # 已经结束的不再提醒
reminded=False
)
evaluations = Evaluation.objects.filter(
status=Evaluation.SCHEDULED,
start__lt=remind_time,
reminded=False
)
targets = [x for x in timeslots] + [y for y in evaluations]
for target in targets:
user_ids = [target.order.parent.user_id]
msg = "[今日有课] 您在 %s-%s,有 %s 老师的 %s 课。带好学习资料,不要迟到哦,点击查看更多课程详情>>" % (
target.start.astimezone().time().strftime("%H:%M"),
target.end.astimezone().time().strftime("%H:%M"),
target.main_teacher.name,
target.subject.name
)
send_push.delay(
msg,
title=Remind.title(Remind.COURSE_REMIND),
user_ids=user_ids,
extras=extras
)
phone = target.order.parent.user.profile.phone
params = {
'starttime': "%s-%s" % (
target.start.astimezone().time().strftime("%H:%M"), target.end.astimezone().time().strftime("%H:%M")),
'teacher': target.main_teacher.name,
'course': target.course_name,
'address': target.school_address,
}
send_sms.delay(phone, TPL_STU_REMIND_COURSE, params=params, times=3)
# 标记为已推送
target.reminded = True
target.save()
return True
@shared_task
def autoRemindCoupons():
# JPush 通知
extras = {
"type": Remind.COUPON_WILL_EXPIRED, # 奖学金即将到期
"code": None
}
remind_time = timezone.now() + Coupon.REMIND_TIME
targets = Coupon.objects.filter(
used=False,
expired_at__gt=timezone.now(),
expired_at__lt=remind_time,
reminded=False
)
for coupon in targets:
user_ids = [coupon.parent.user_id]
msg = "您有一张%d元的奖学金券即将到期,快去使用吧>>" % (
coupon.amount_yuan
)
send_push.delay(
msg,
title=Remind.title(Remind.COUPON_WILL_EXPIRED),
user_ids=user_ids,
extras=extras
)
# 标记为已推送
coupon.reminded = True
coupon.save()
@shared_task
def send_push(msg, user_ids=None, extras=None, title=None):
'''
user_ids is a list of user_id [1, 2, ...]
if user_ids is None then send to all
'''
app_key = settings.JPUSH_APP_KEY
master_secret = settings.JPUSH_MASTER_SECRET
_jpush = jpush.JPush(app_key, master_secret)
push = _jpush.create_push()
ios_msg = jpush.ios(alert=msg, extras=extras)
android_msg = jpush.android(alert=msg, extras=extras, title=title)
push.notification = jpush.notification(
alert=msg, android=android_msg, ios=ios_msg)
push.platform = jpush.all_
# for ios dev or prd env
options = dict()
options['apns_production'] = settings.APNS_PRODUCTION
jpush.options(options)
if user_ids is None:
push.audience = jpush.all_
return str(push.send())
elif len(user_ids) > 1000:
ans = []
for i in range(len(user_ids) // 1000 + 1):
ret = send_push(msg, user_ids[i * 1000: (i + 1) * 1000])
ans.append(ret)
return ans
elif len(user_ids) == 0:
return ''
else:
push.audience = jpush.audience(
jpush.alias(*user_ids)
)
return str(push.send())
@shared_task
def autoCancelOrders():
operateTargets = Order.objects.should_auto_canceled_objects()
logger.debug("[autoCancelOrders] estimated target amount:%d" %(len(operateTargets)))
count = 0
for order in operateTargets:
if Order.objects.filter(pk=order.id, status=Order.PENDING).update(status=Order.CANCELED):
order.cancel()
count += 1
logger.debug("[autoCancelOrders] The Order created at %s which order_id is %s, was been canceled automatically" %(order.created_at, order.order_id))
if count > 0:
logger.debug("[autoCancelOrders] effected target amount:%d" % count)
return True
@shared_task
def autoAddTeacherTeachingAge():
cpmStartDate = timezone.now()
try:
cpmStartDate = cpmStartDate.replace(year=int(cpmStartDate.strftime("%Y"))-1, hour=0, minute=0, second=0, microsecond=0)
except:
cpmStartDate -= datetime.timedelta(days=1)
cpmStartDate = cpmStartDate.replace(year=int(cpmStartDate.strftime("%Y"))-1, hour=0, minute=0, second=0, microsecond=0)
# cpmStartDate = cpmStartDate.replace(year=2015, month=12, day=31, hour=0, minute=0, second=0, microsecond=0)
cpmEndDate = cpmStartDate.replace(hour=23, minute=59, second=59, microsecond=999999)
tempAll = Teacher.objects.filter(user__date_joined__gte=cpmStartDate, user__date_joined__lte=cpmEndDate)
for teacher in tempAll:
teacher.teaching_age += 1
teacher.save()
return True;
@shared_task
def registerKuaiLeXueUserByOrder(oid):
'''
注册快乐学用户, 订单付款后, 把学生和老师注册到快乐学, 并关联师生关系
:param oid: models.Order.id
:return: True or not
'''
logger.debug("[registerKuaiLeXueUserByOrder] order id: %s" % oid)
order = Order.objects.get(pk=oid)
parent = order.parent
teacher = order.teacher
klx_stu_name = klx_reg_student(parent)
if not klx_stu_name: # just try again
klx_stu_name = klx_reg_student(parent)
if not klx_stu_name:
return False
klx_tea_name = klx_reg_teacher(teacher)
if not klx_tea_name: # just try again
klx_tea_name = klx_reg_teacher(teacher)
if not klx_tea_name:
return False
ok = klx_relation(klx_tea_name, klx_stu_name)
if not ok: # just try again
ok = klx_relation(klx_tea_name, klx_stu_name)
return ok
@shared_task(bind=True, default_retry_delay=32, max_retries=4)
def send_sms(self, phone, tpl_id, params=None, times=1):
if params is None:
params = {}
logger.debug("[send_sms] to "+str(phone)+', '+str(tpl_id)+': '+str(params))
try:
tpl_send_sms(phone, tpl_id, params)
except Exception as exc:
# request.retries is an integer starting at 0
if self.request.retries + 1 < times:
raise self.retry(exc=exc)
logger.error(exc)
raise exc
@shared_task
def autoCreateSchoolIncomeRecord():
all_schools = School.objects.filter(opened=True)
logger.debug("[autoCreateSchoolIncomeRecord] all schools: %d" % len(all_schools))
now = timezone.localtime(timezone.now())
yesterday = now - datetime.timedelta(hours=now.hour + 1)
ok_count = 0
logger.debug('[autoCreateSchoolIncomeRecord] end time: %s' % yesterday)
for school in all_schools:
created = school.create_income_record(yesterday)
if created:
ok_count += 1
logger.debug("[autoCreateSchoolIncomeRecord] %s" % school.name)
logger.debug("[autoCreateSchoolIncomeRecord] %d schools end." % ok_count)
return True
@shared_task
def autoNotifyExerciseMistakes():
# 需要通知的课程
NOTIFY_DELAY = datetime.timedelta(minutes=10)
lc_tss = LiveCourseTimeSlot.objects.filter(
mistakes_pushed=False,
end__lte=timezone.now() - NOTIFY_DELAY,
)
logger.debug("[autoNotifyExerciseMistakes] %d live course found" % (
lc_tss.count()))
# 有错题的用户列表
user_ids = list()
for lc_ts in lc_tss:
ess = ExerciseSubmit.objects.filter(
exercise_session__is_active=False,
exercise_session__live_course_timeslot=lc_ts,
).exclude(question__solution=F('option')).distinct('parent')
user_ids += [es.parent.user_id for es in ess]
user_ids = list(set(user_ids))
logger.debug(
"[autoNotifyExerciseMistakes] users count: %d" % (len(user_ids)))
# JPush 通知
extras = {
"type": Remind.EXERCISE_MISTAKES, # 错题本更新
"code": None
}
send_push.delay(
"[专属错题本] 小狮已帮你把课上答错的题收进错题本啦,内附私密解析,快去看看哦>>",
title=Remind.title(Remind.EXERCISE_MISTAKES),
user_ids=user_ids,
extras=extras
)
lc_tss.update(mistakes_pushed=True)
return True