zou 0.19.15__py3-none-any.whl → 0.20.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zou/__init__.py +1 -1
- zou/app/__init__.py +10 -2
- zou/app/api.py +2 -0
- zou/app/blueprints/assets/__init__.py +22 -0
- zou/app/blueprints/assets/resources.py +241 -4
- zou/app/blueprints/auth/__init__.py +4 -0
- zou/app/blueprints/auth/resources.py +154 -22
- zou/app/blueprints/breakdown/resources.py +4 -4
- zou/app/blueprints/chats/__init__.py +22 -0
- zou/app/blueprints/chats/resources.py +199 -0
- zou/app/blueprints/comments/resources.py +36 -19
- zou/app/blueprints/crud/__init__.py +12 -0
- zou/app/blueprints/crud/attachment_file.py +14 -5
- zou/app/blueprints/crud/base.py +29 -28
- zou/app/blueprints/crud/chat.py +13 -0
- zou/app/blueprints/crud/chat_message.py +13 -0
- zou/app/blueprints/crud/comments.py +85 -29
- zou/app/blueprints/crud/custom_action.py +1 -1
- zou/app/blueprints/crud/day_off.py +47 -9
- zou/app/blueprints/crud/department.py +1 -25
- zou/app/blueprints/crud/entity.py +46 -5
- zou/app/blueprints/crud/entity_type.py +13 -1
- zou/app/blueprints/crud/event.py +1 -1
- zou/app/blueprints/crud/file_status.py +1 -1
- zou/app/blueprints/crud/metadata_descriptor.py +24 -10
- zou/app/blueprints/crud/organisation.py +22 -5
- zou/app/blueprints/crud/output_file.py +1 -1
- zou/app/blueprints/crud/output_type.py +1 -1
- zou/app/blueprints/crud/person.py +32 -24
- zou/app/blueprints/crud/playlist.py +1 -1
- zou/app/blueprints/crud/preview_background_file.py +6 -7
- zou/app/blueprints/crud/preview_file.py +1 -1
- zou/app/blueprints/crud/project.py +14 -6
- zou/app/blueprints/crud/project_status.py +1 -1
- zou/app/blueprints/crud/schedule_item.py +4 -2
- zou/app/blueprints/crud/software.py +1 -1
- zou/app/blueprints/crud/status_automation.py +1 -1
- zou/app/blueprints/crud/studio.py +33 -0
- zou/app/blueprints/crud/task.py +47 -3
- zou/app/blueprints/crud/task_status.py +1 -1
- zou/app/blueprints/crud/task_type.py +4 -4
- zou/app/blueprints/crud/working_file.py +4 -8
- zou/app/blueprints/events/resources.py +13 -12
- zou/app/blueprints/export/csv/assets.py +15 -6
- zou/app/blueprints/export/csv/edits.py +15 -5
- zou/app/blueprints/export/csv/playlists.py +1 -1
- zou/app/blueprints/export/csv/shots.py +15 -5
- zou/app/blueprints/export/csv/time_spents.py +1 -1
- zou/app/blueprints/files/resources.py +22 -23
- zou/app/blueprints/index/resources.py +38 -29
- zou/app/blueprints/news/resources.py +25 -11
- zou/app/blueprints/persons/__init__.py +5 -2
- zou/app/blueprints/persons/resources.py +126 -120
- zou/app/blueprints/previews/__init__.py +18 -8
- zou/app/blueprints/previews/resources.py +569 -328
- zou/app/blueprints/projects/resources.py +1 -1
- zou/app/blueprints/search/resources.py +18 -6
- zou/app/blueprints/shots/__init__.py +5 -0
- zou/app/blueprints/shots/resources.py +134 -4
- zou/app/blueprints/source/__init__.py +6 -6
- zou/app/blueprints/source/csv/assets.py +10 -3
- zou/app/blueprints/source/csv/base.py +1 -1
- zou/app/blueprints/source/csv/edits.py +10 -3
- zou/app/blueprints/source/csv/shots.py +10 -3
- zou/app/blueprints/source/{edl.py → otio.py} +82 -41
- zou/app/blueprints/tasks/__init__.py +3 -2
- zou/app/blueprints/tasks/resources.py +83 -52
- zou/app/blueprints/user/__init__.py +9 -0
- zou/app/blueprints/user/resources.py +170 -12
- zou/app/config.py +10 -0
- zou/app/mixin.py +6 -5
- zou/app/models/attachment_file.py +10 -4
- zou/app/models/base.py +18 -13
- zou/app/models/build_job.py +7 -4
- zou/app/models/chat.py +44 -0
- zou/app/models/chat_message.py +37 -0
- zou/app/models/comment.py +1 -0
- zou/app/models/day_off.py +3 -0
- zou/app/models/entity.py +4 -6
- zou/app/models/entity_type.py +2 -0
- zou/app/models/organisation.py +14 -15
- zou/app/models/person.py +6 -1
- zou/app/models/project.py +3 -0
- zou/app/models/search_filter.py +11 -0
- zou/app/models/search_filter_group.py +10 -0
- zou/app/models/serializer.py +17 -17
- zou/app/models/status_automation.py +2 -0
- zou/app/models/studio.py +13 -0
- zou/app/models/subscription.py +2 -2
- zou/app/models/task.py +6 -1
- zou/app/models/task_status.py +1 -0
- zou/app/models/task_type.py +1 -0
- zou/app/models/working_file.py +1 -1
- zou/app/services/assets_service.py +101 -14
- zou/app/services/auth_service.py +17 -44
- zou/app/services/breakdown_service.py +37 -5
- zou/app/services/chats_service.py +279 -0
- zou/app/services/comments_service.py +110 -65
- zou/app/services/concepts_service.py +4 -12
- zou/app/services/deletion_service.py +43 -30
- zou/app/services/edits_service.py +5 -11
- zou/app/services/emails_service.py +4 -4
- zou/app/services/entities_service.py +17 -2
- zou/app/services/events_service.py +12 -4
- zou/app/services/exception.py +5 -5
- zou/app/services/names_service.py +7 -2
- zou/app/services/news_service.py +17 -9
- zou/app/services/persons_service.py +38 -21
- zou/app/services/playlists_service.py +8 -7
- zou/app/services/preview_files_service.py +137 -10
- zou/app/services/projects_service.py +5 -14
- zou/app/services/shots_service.py +221 -49
- zou/app/services/sync_service.py +46 -42
- zou/app/services/tasks_service.py +185 -46
- zou/app/services/time_spents_service.py +67 -20
- zou/app/services/user_service.py +350 -107
- zou/app/stores/auth_tokens_store.py +2 -1
- zou/app/stores/file_store.py +18 -0
- zou/app/stores/publisher_store.py +7 -7
- zou/app/stores/queue_store.py +1 -0
- zou/app/swagger.py +36 -20
- zou/app/utils/cache.py +2 -0
- zou/app/utils/commands.py +104 -7
- zou/app/utils/csv_utils.py +1 -4
- zou/app/utils/date_helpers.py +33 -17
- zou/app/utils/dbhelpers.py +14 -1
- zou/app/utils/emails.py +2 -2
- zou/app/utils/fido.py +22 -0
- zou/app/utils/query.py +54 -6
- zou/app/utils/redis.py +11 -0
- zou/app/utils/saml.py +51 -0
- zou/app/utils/string.py +2 -0
- zou/app/utils/thumbnail.py +4 -2
- zou/cli.py +76 -18
- zou/debug.py +4 -2
- zou/event_stream.py +122 -165
- zou/job_settings.py +1 -0
- zou/migrations/env.py +0 -0
- zou/migrations/utils/base.py +6 -6
- zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
- zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
- zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
- zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
- zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
- zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
- zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
- zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
- zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
- zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
- zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
- zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
- zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
- zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
- zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
- zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
- zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
- zou/remote/config_payload.py +2 -1
- zou/utils/movie.py +14 -4
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/RECORD +163 -134
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
|
@@ -2,7 +2,7 @@ from datetime import timedelta
|
|
|
2
2
|
from operator import itemgetter
|
|
3
3
|
from sqlalchemy.orm import aliased
|
|
4
4
|
from sqlalchemy.exc import IntegrityError, StatementError
|
|
5
|
-
from sqlalchemy import func
|
|
5
|
+
from sqlalchemy import func, or_
|
|
6
6
|
|
|
7
7
|
from zou.app.utils import (
|
|
8
8
|
cache,
|
|
@@ -20,6 +20,7 @@ from zou.app.models.entity import (
|
|
|
20
20
|
)
|
|
21
21
|
from zou.app.models.person import Person
|
|
22
22
|
from zou.app.models.project import Project
|
|
23
|
+
from zou.app.models.preview_file import PreviewFile
|
|
23
24
|
from zou.app.models.schedule_item import ScheduleItem
|
|
24
25
|
from zou.app.models.subscription import Subscription
|
|
25
26
|
from zou.app.models.task import Task
|
|
@@ -49,7 +50,7 @@ from zou.app.services.exception import (
|
|
|
49
50
|
|
|
50
51
|
def clear_shot_cache(shot_id):
|
|
51
52
|
cache.cache.delete_memoized(get_shot, shot_id)
|
|
52
|
-
cache.cache.delete_memoized(
|
|
53
|
+
cache.cache.delete_memoized(get_shot, shot_id, True)
|
|
53
54
|
cache.cache.delete_memoized(get_full_shot, shot_id)
|
|
54
55
|
|
|
55
56
|
|
|
@@ -250,8 +251,10 @@ def get_shots_and_tasks(criterions={}):
|
|
|
250
251
|
Task.end_date,
|
|
251
252
|
Task.start_date,
|
|
252
253
|
Task.due_date,
|
|
254
|
+
Task.done_date,
|
|
253
255
|
Task.last_comment_date,
|
|
254
256
|
Task.nb_assets_ready,
|
|
257
|
+
Task.difficulty,
|
|
255
258
|
assignees_table.columns.person,
|
|
256
259
|
Project.id,
|
|
257
260
|
Project.name,
|
|
@@ -299,8 +302,10 @@ def get_shots_and_tasks(criterions={}):
|
|
|
299
302
|
task_end_date,
|
|
300
303
|
task_start_date,
|
|
301
304
|
task_due_date,
|
|
305
|
+
task_done_date,
|
|
302
306
|
task_last_comment_date,
|
|
303
307
|
task_nb_assets_ready,
|
|
308
|
+
task_difficulty,
|
|
304
309
|
person_id,
|
|
305
310
|
project_id,
|
|
306
311
|
project_name,
|
|
@@ -354,6 +359,7 @@ def get_shots_and_tasks(criterions={}):
|
|
|
354
359
|
"duration": task_duration,
|
|
355
360
|
"due_date": task_due_date,
|
|
356
361
|
"end_date": task_end_date,
|
|
362
|
+
"done_date": task_done_date,
|
|
357
363
|
"entity_id": shot_id,
|
|
358
364
|
"estimation": task_estimation,
|
|
359
365
|
"is_subscribed": subscription_map.get(task_id, False),
|
|
@@ -363,6 +369,7 @@ def get_shots_and_tasks(criterions={}):
|
|
|
363
369
|
"real_start_date": task_real_start_date,
|
|
364
370
|
"retake_count": task_retake_count,
|
|
365
371
|
"start_date": task_start_date,
|
|
372
|
+
"difficulty": task_difficulty,
|
|
366
373
|
"task_status_id": task_status_id,
|
|
367
374
|
"task_type_id": task_type_id,
|
|
368
375
|
"assignees": [],
|
|
@@ -395,19 +402,13 @@ def get_shot_raw(shot_id):
|
|
|
395
402
|
|
|
396
403
|
|
|
397
404
|
@cache.memoize_function(120)
|
|
398
|
-
def get_shot(shot_id):
|
|
405
|
+
def get_shot(shot_id, relations=False):
|
|
399
406
|
"""
|
|
400
407
|
Return given shot as a dictionary.
|
|
401
408
|
"""
|
|
402
|
-
return get_shot_raw(shot_id).serialize(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
@cache.memoize_function(120)
|
|
406
|
-
def get_shot_with_relations(shot_id):
|
|
407
|
-
"""
|
|
408
|
-
Return given shot as a dictionary.
|
|
409
|
-
"""
|
|
410
|
-
return get_shot_raw(shot_id).serialize(obj_type="Shot", relations=True)
|
|
409
|
+
return get_shot_raw(shot_id).serialize(
|
|
410
|
+
obj_type="Shot", relations=relations
|
|
411
|
+
)
|
|
411
412
|
|
|
412
413
|
|
|
413
414
|
@cache.memoize_function(120)
|
|
@@ -419,7 +420,7 @@ def get_full_shot(shot_id):
|
|
|
419
420
|
shots = get_shots_and_tasks({"id": shot_id})
|
|
420
421
|
if len(shots) > 0:
|
|
421
422
|
shot = shots[0]
|
|
422
|
-
shot.update(
|
|
423
|
+
shot.update(get_shot(shot_id, relations=True))
|
|
423
424
|
return shot
|
|
424
425
|
else:
|
|
425
426
|
raise ShotNotFoundException
|
|
@@ -1112,24 +1113,31 @@ def get_base_entity_type_name(entity_dict):
|
|
|
1112
1113
|
return type_name
|
|
1113
1114
|
|
|
1114
1115
|
|
|
1115
|
-
def get_weighted_quotas(
|
|
1116
|
+
def get_weighted_quotas(
|
|
1117
|
+
project_id, task_type_id, studio_id=None, feedback=True
|
|
1118
|
+
):
|
|
1116
1119
|
"""
|
|
1117
1120
|
Build quota statistics. It counts the number of frames done for each day.
|
|
1118
|
-
A shot is considered done at the first feedback request
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1121
|
+
A shot is considered done at the first feedback request or at last
|
|
1122
|
+
approval.
|
|
1123
|
+
|
|
1124
|
+
If time spent is filled for it, it weights the result with the frame
|
|
1125
|
+
number with the time spents. If there is no time spent, it considers that
|
|
1126
|
+
the work was done from the wip date to the feedback date (or approval date).
|
|
1122
1127
|
It computes the shot count and the number of seconds too.
|
|
1128
|
+
|
|
1129
|
+
If the `feedback` flag is set to True, it uses the feedback date
|
|
1130
|
+
(real_end_date), if feedback is set to False, it uses the approval date
|
|
1131
|
+
(done_date).
|
|
1123
1132
|
"""
|
|
1124
1133
|
fps = projects_service.get_project_fps(project_id)
|
|
1125
1134
|
timezone = user_service.get_timezone()
|
|
1126
1135
|
shot_type = get_shot_type()
|
|
1127
1136
|
quotas = {}
|
|
1128
1137
|
query = (
|
|
1129
|
-
Task.query.filter(
|
|
1130
|
-
.filter(
|
|
1138
|
+
Task.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1139
|
+
.filter(Task.project_id == project_id)
|
|
1131
1140
|
.filter(Task.task_type_id == task_type_id)
|
|
1132
|
-
.filter(Task.end_date != None)
|
|
1133
1141
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1134
1142
|
.join(Project, Project.id == Task.project_id)
|
|
1135
1143
|
.join(TimeSpent, Task.id == TimeSpent.task_id)
|
|
@@ -1140,6 +1148,19 @@ def get_weighted_quotas(project_id, task_type_id, detail_level):
|
|
|
1140
1148
|
TimeSpent.person_id,
|
|
1141
1149
|
)
|
|
1142
1150
|
)
|
|
1151
|
+
|
|
1152
|
+
if feedback:
|
|
1153
|
+
query = query.filter(Task.end_date != None)
|
|
1154
|
+
else:
|
|
1155
|
+
query = query.filter(Task.done_date != None)
|
|
1156
|
+
|
|
1157
|
+
if studio_id is not None:
|
|
1158
|
+
persons_from_studio = Person.query.filter(
|
|
1159
|
+
Person.studio_id == studio_id
|
|
1160
|
+
).all()
|
|
1161
|
+
query = query.filter(
|
|
1162
|
+
or_(*[Task.assignees.contains(p) for p in persons_from_studio])
|
|
1163
|
+
)
|
|
1143
1164
|
result = query.all()
|
|
1144
1165
|
|
|
1145
1166
|
for task, nb_frames, date, duration, person_id in result:
|
|
@@ -1153,7 +1174,6 @@ def get_weighted_quotas(project_id, task_type_id, detail_level):
|
|
|
1153
1174
|
.filter(Entity.entity_type_id == shot_type["id"])
|
|
1154
1175
|
.filter(Task.task_type_id == task_type_id)
|
|
1155
1176
|
.filter(Task.real_start_date != None)
|
|
1156
|
-
.filter(Task.end_date != None)
|
|
1157
1177
|
.filter(TimeSpent.id == None)
|
|
1158
1178
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1159
1179
|
.join(Project, Project.id == Task.project_id)
|
|
@@ -1161,19 +1181,32 @@ def get_weighted_quotas(project_id, task_type_id, detail_level):
|
|
|
1161
1181
|
.join(Task.assignees)
|
|
1162
1182
|
.add_columns(Entity.nb_frames, Person.id)
|
|
1163
1183
|
)
|
|
1184
|
+
|
|
1185
|
+
if feedback:
|
|
1186
|
+
query = query.filter(Task.end_date != None)
|
|
1187
|
+
else:
|
|
1188
|
+
query = query.filter(Task.done_date != None)
|
|
1189
|
+
|
|
1190
|
+
if studio_id is not None:
|
|
1191
|
+
query = query.filter(
|
|
1192
|
+
or_(*[Task.assignees.contains(p) for p in persons_from_studio])
|
|
1193
|
+
)
|
|
1164
1194
|
result = query.all()
|
|
1165
1195
|
|
|
1166
1196
|
for task, nb_frames, person_id in result:
|
|
1197
|
+
date = task.done_date
|
|
1198
|
+
if feedback:
|
|
1199
|
+
date = task.end_date
|
|
1200
|
+
|
|
1167
1201
|
business_days = (
|
|
1168
|
-
date_helpers.get_business_days(task.real_start_date,
|
|
1169
|
-
+ 1
|
|
1202
|
+
date_helpers.get_business_days(task.real_start_date, date) + 1
|
|
1170
1203
|
)
|
|
1171
1204
|
if nb_frames is not None:
|
|
1172
1205
|
nb_frames = round(nb_frames / business_days) or 0
|
|
1173
1206
|
else:
|
|
1174
1207
|
nb_frames = 0
|
|
1175
|
-
|
|
1176
|
-
for x in range((
|
|
1208
|
+
|
|
1209
|
+
for x in range((date - task.real_start_date).days + 1):
|
|
1177
1210
|
if date.weekday() < 5:
|
|
1178
1211
|
_add_quota_entry(
|
|
1179
1212
|
quotas, str(person_id), date, timezone, nb_frames, fps
|
|
@@ -1182,11 +1215,13 @@ def get_weighted_quotas(project_id, task_type_id, detail_level):
|
|
|
1182
1215
|
return quotas
|
|
1183
1216
|
|
|
1184
1217
|
|
|
1185
|
-
def get_raw_quotas(project_id, task_type_id,
|
|
1218
|
+
def get_raw_quotas(project_id, task_type_id, studio_id=None, feedback=True):
|
|
1186
1219
|
"""
|
|
1187
1220
|
Build quota statistics in a raw way. It counts the number of frames done
|
|
1188
1221
|
for each day. A shot is considered done at the first feedback request (end
|
|
1189
|
-
date)
|
|
1222
|
+
date) or approval date (done_date).
|
|
1223
|
+
|
|
1224
|
+
It considers that all the work was done at the end date.
|
|
1190
1225
|
It computes the shot count and the number of seconds too.
|
|
1191
1226
|
"""
|
|
1192
1227
|
fps = projects_service.get_project_fps(project_id)
|
|
@@ -1197,16 +1232,32 @@ def get_raw_quotas(project_id, task_type_id, detail_level):
|
|
|
1197
1232
|
Task.query.filter(Task.project_id == project_id)
|
|
1198
1233
|
.filter(Entity.entity_type_id == shot_type["id"])
|
|
1199
1234
|
.filter(Task.task_type_id == task_type_id)
|
|
1200
|
-
.filter(Task.end_date != None)
|
|
1201
1235
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1202
1236
|
.join(Project, Project.id == Task.project_id)
|
|
1203
1237
|
.join(Task.assignees)
|
|
1204
1238
|
.add_columns(Entity.nb_frames, Person.id)
|
|
1205
1239
|
)
|
|
1240
|
+
|
|
1241
|
+
if feedback:
|
|
1242
|
+
query = query.filter(Task.end_date != None)
|
|
1243
|
+
else:
|
|
1244
|
+
query = query.filter(Task.done_date != None)
|
|
1245
|
+
|
|
1246
|
+
if studio_id is not None:
|
|
1247
|
+
persons_from_studio = Person.query.filter(
|
|
1248
|
+
Person.studio_id == studio_id
|
|
1249
|
+
).all()
|
|
1250
|
+
query = query.filter(
|
|
1251
|
+
or_(*[Task.assignees.contains(p) for p in persons_from_studio])
|
|
1252
|
+
)
|
|
1253
|
+
|
|
1206
1254
|
result = query.all()
|
|
1207
1255
|
|
|
1208
1256
|
for task, nb_frames, person_id in result:
|
|
1209
|
-
date = task.
|
|
1257
|
+
date = task.done_date
|
|
1258
|
+
if feedback:
|
|
1259
|
+
date = task.end_date
|
|
1260
|
+
|
|
1210
1261
|
if nb_frames is None:
|
|
1211
1262
|
nb_frames = 0
|
|
1212
1263
|
_add_quota_entry(
|
|
@@ -1280,7 +1331,13 @@ def _init_quota_person(quotas, person_id):
|
|
|
1280
1331
|
|
|
1281
1332
|
|
|
1282
1333
|
def get_month_quota_shots(
|
|
1283
|
-
person_id,
|
|
1334
|
+
person_id,
|
|
1335
|
+
year,
|
|
1336
|
+
month,
|
|
1337
|
+
project_id=None,
|
|
1338
|
+
task_type_id=None,
|
|
1339
|
+
weighted=True,
|
|
1340
|
+
feedback=True,
|
|
1284
1341
|
):
|
|
1285
1342
|
"""
|
|
1286
1343
|
Return shots that are included in quota comptutation for given
|
|
@@ -1295,6 +1352,7 @@ def get_month_quota_shots(
|
|
|
1295
1352
|
end,
|
|
1296
1353
|
project_id=project_id,
|
|
1297
1354
|
task_type_id=task_type_id,
|
|
1355
|
+
feedback=feedback,
|
|
1298
1356
|
)
|
|
1299
1357
|
else:
|
|
1300
1358
|
return get_raw_quota_shots_between(
|
|
@@ -1303,11 +1361,18 @@ def get_month_quota_shots(
|
|
|
1303
1361
|
end,
|
|
1304
1362
|
project_id=project_id,
|
|
1305
1363
|
task_type_id=task_type_id,
|
|
1364
|
+
feedback=feedback,
|
|
1306
1365
|
)
|
|
1307
1366
|
|
|
1308
1367
|
|
|
1309
1368
|
def get_week_quota_shots(
|
|
1310
|
-
person_id,
|
|
1369
|
+
person_id,
|
|
1370
|
+
year,
|
|
1371
|
+
week,
|
|
1372
|
+
project_id=None,
|
|
1373
|
+
task_type_id=None,
|
|
1374
|
+
weighted=True,
|
|
1375
|
+
feedback=True,
|
|
1311
1376
|
):
|
|
1312
1377
|
"""
|
|
1313
1378
|
Return shots that are included in quota comptutation for given
|
|
@@ -1322,6 +1387,7 @@ def get_week_quota_shots(
|
|
|
1322
1387
|
end,
|
|
1323
1388
|
project_id=project_id,
|
|
1324
1389
|
task_type_id=task_type_id,
|
|
1390
|
+
feedback=feedback,
|
|
1325
1391
|
)
|
|
1326
1392
|
else:
|
|
1327
1393
|
return get_raw_quota_shots_between(
|
|
@@ -1330,6 +1396,7 @@ def get_week_quota_shots(
|
|
|
1330
1396
|
end,
|
|
1331
1397
|
project_id=project_id,
|
|
1332
1398
|
task_type_id=task_type_id,
|
|
1399
|
+
feedback=feedback,
|
|
1333
1400
|
)
|
|
1334
1401
|
|
|
1335
1402
|
|
|
@@ -1341,13 +1408,14 @@ def get_day_quota_shots(
|
|
|
1341
1408
|
project_id=None,
|
|
1342
1409
|
task_type_id=None,
|
|
1343
1410
|
weighted=True,
|
|
1411
|
+
feedback=True,
|
|
1344
1412
|
):
|
|
1345
1413
|
"""
|
|
1346
1414
|
Return shots that are included in quota comptutation for given
|
|
1347
1415
|
person and day.
|
|
1348
1416
|
"""
|
|
1349
1417
|
start, end = date_helpers.get_day_interval(year, month, day)
|
|
1350
|
-
start, end = _get_timezoned_interval(start, end)
|
|
1418
|
+
# start, end = _get_timezoned_interval(start, end)
|
|
1351
1419
|
if weighted:
|
|
1352
1420
|
return get_weighted_quota_shots_between(
|
|
1353
1421
|
person_id,
|
|
@@ -1355,6 +1423,7 @@ def get_day_quota_shots(
|
|
|
1355
1423
|
end,
|
|
1356
1424
|
project_id=project_id,
|
|
1357
1425
|
task_type_id=task_type_id,
|
|
1426
|
+
feedback=feedback,
|
|
1358
1427
|
)
|
|
1359
1428
|
else:
|
|
1360
1429
|
return get_raw_quota_shots_between(
|
|
@@ -1363,11 +1432,12 @@ def get_day_quota_shots(
|
|
|
1363
1432
|
end,
|
|
1364
1433
|
project_id=project_id,
|
|
1365
1434
|
task_type_id=task_type_id,
|
|
1435
|
+
feedback=feedback,
|
|
1366
1436
|
)
|
|
1367
1437
|
|
|
1368
1438
|
|
|
1369
1439
|
def get_weighted_quota_shots_between(
|
|
1370
|
-
person_id, start, end, project_id=None, task_type_id=None
|
|
1440
|
+
person_id, start, end, project_id=None, task_type_id=None, feedback=True
|
|
1371
1441
|
):
|
|
1372
1442
|
"""
|
|
1373
1443
|
Get all shots leading to a quota computation during the given period.
|
|
@@ -1387,7 +1457,6 @@ def get_weighted_quota_shots_between(
|
|
|
1387
1457
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1388
1458
|
.filter(Task.project_id == project_id)
|
|
1389
1459
|
.filter(Task.task_type_id == task_type_id)
|
|
1390
|
-
.filter(Task.end_date != None)
|
|
1391
1460
|
.filter(TimeSpent.person_id == person_id)
|
|
1392
1461
|
.filter(TimeSpent.date >= func.cast(start, TimeSpent.date.type))
|
|
1393
1462
|
.filter(TimeSpent.date < func.cast(end, TimeSpent.date.type))
|
|
@@ -1396,11 +1465,17 @@ def get_weighted_quota_shots_between(
|
|
|
1396
1465
|
.join(TimeSpent, Task.id == TimeSpent.task_id)
|
|
1397
1466
|
.add_columns(Task.duration, TimeSpent.duration)
|
|
1398
1467
|
)
|
|
1468
|
+
|
|
1469
|
+
if feedback:
|
|
1470
|
+
query = query.filter(Task.end_date != None)
|
|
1471
|
+
else:
|
|
1472
|
+
query = query.filter(Task.done_date != None)
|
|
1473
|
+
|
|
1399
1474
|
query_shots = query.all()
|
|
1400
1475
|
for entity, task_duration, duration in query_shots:
|
|
1401
1476
|
shot = entity.serialize()
|
|
1402
1477
|
if shot["id"] not in already_listed:
|
|
1403
|
-
full_name, _ = names_service.get_full_entity_name(shot["id"])
|
|
1478
|
+
full_name, _, _ = names_service.get_full_entity_name(shot["id"])
|
|
1404
1479
|
shot["full_name"] = full_name
|
|
1405
1480
|
shot["weight"] = round(duration / task_duration, 2) or 0
|
|
1406
1481
|
shots.append(shot)
|
|
@@ -1409,22 +1484,36 @@ def get_weighted_quota_shots_between(
|
|
|
1409
1484
|
shot = already_listed[shot["id"]]
|
|
1410
1485
|
shot["weight"] += round(duration / task_duration, 2)
|
|
1411
1486
|
|
|
1412
|
-
start
|
|
1413
|
-
|
|
1487
|
+
print(start, end)
|
|
1488
|
+
if type(start) is str:
|
|
1489
|
+
start = date_helpers.get_datetime_from_string(start)
|
|
1490
|
+
if type(end) is str:
|
|
1491
|
+
end = date_helpers.get_datetime_from_string(end)
|
|
1414
1492
|
query = (
|
|
1415
1493
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1416
1494
|
.filter(Task.project_id == project_id)
|
|
1417
1495
|
.filter(Task.task_type_id == task_type_id)
|
|
1418
|
-
.filter(Task.end_date != None)
|
|
1419
1496
|
.filter(Task.real_start_date != None)
|
|
1420
1497
|
.filter(Task.assignees.contains(person))
|
|
1421
|
-
.filter((Task.real_start_date <= end) & (Task.end_date >= start))
|
|
1422
1498
|
.filter(TimeSpent.id == None)
|
|
1423
1499
|
.join(Task, Entity.id == Task.entity_id)
|
|
1424
1500
|
.join(Project, Project.id == Task.project_id)
|
|
1425
1501
|
.outerjoin(TimeSpent, TimeSpent.task_id == Task.id)
|
|
1426
|
-
.add_columns(Task.real_start_date, Task.end_date)
|
|
1427
1502
|
)
|
|
1503
|
+
|
|
1504
|
+
if feedback:
|
|
1505
|
+
query = (
|
|
1506
|
+
query.filter(Task.end_date != None)
|
|
1507
|
+
.filter((Task.real_start_date <= end) & (Task.end_date >= start))
|
|
1508
|
+
.add_columns(Task.real_start_date, Task.end_date)
|
|
1509
|
+
)
|
|
1510
|
+
else:
|
|
1511
|
+
query = (
|
|
1512
|
+
query.filter(Task.done_date != None)
|
|
1513
|
+
.filter((Task.real_start_date <= end) & (Task.done_date >= start))
|
|
1514
|
+
.add_columns(Task.real_start_date, Task.done_date)
|
|
1515
|
+
)
|
|
1516
|
+
|
|
1428
1517
|
query_shots = query.all()
|
|
1429
1518
|
|
|
1430
1519
|
for entity, task_start, task_end in query_shots:
|
|
@@ -1433,7 +1522,7 @@ def get_weighted_quota_shots_between(
|
|
|
1433
1522
|
business_days = (
|
|
1434
1523
|
date_helpers.get_business_days(task_start, task_end) + 1
|
|
1435
1524
|
)
|
|
1436
|
-
full_name, _ = names_service.get_full_entity_name(shot["id"])
|
|
1525
|
+
full_name, _, _ = names_service.get_full_entity_name(shot["id"])
|
|
1437
1526
|
shot["full_name"] = full_name
|
|
1438
1527
|
multiplicator = 1
|
|
1439
1528
|
if task_start >= start and task_end <= end:
|
|
@@ -1454,7 +1543,7 @@ def get_weighted_quota_shots_between(
|
|
|
1454
1543
|
|
|
1455
1544
|
|
|
1456
1545
|
def get_raw_quota_shots_between(
|
|
1457
|
-
person_id, start, end, project_id=None, task_type_id=None
|
|
1546
|
+
person_id, start, end, project_id=None, task_type_id=None, feedback=True
|
|
1458
1547
|
):
|
|
1459
1548
|
"""
|
|
1460
1549
|
Get all shots leading to a quota computation during the given period.
|
|
@@ -1467,21 +1556,31 @@ def get_raw_quota_shots_between(
|
|
|
1467
1556
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1468
1557
|
.filter(Task.project_id == project_id)
|
|
1469
1558
|
.filter(Task.task_type_id == task_type_id)
|
|
1470
|
-
.filter(
|
|
1559
|
+
.filter(Task.assignees.contains(person))
|
|
1560
|
+
.join(Task, Entity.id == Task.entity_id)
|
|
1561
|
+
.join(Project, Project.id == Task.project_id)
|
|
1562
|
+
)
|
|
1563
|
+
|
|
1564
|
+
if feedback:
|
|
1565
|
+
query = query.filter(
|
|
1471
1566
|
Task.end_date.between(
|
|
1472
1567
|
func.cast(start, Task.end_date.type),
|
|
1473
1568
|
func.cast(end, Task.end_date.type),
|
|
1474
1569
|
)
|
|
1475
1570
|
)
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1571
|
+
else:
|
|
1572
|
+
query = query.filter(
|
|
1573
|
+
Task.done_date.between(
|
|
1574
|
+
func.cast(start, Task.done_date.type),
|
|
1575
|
+
func.cast(end, Task.done_date.type),
|
|
1576
|
+
)
|
|
1577
|
+
)
|
|
1578
|
+
|
|
1480
1579
|
query_shots = query.all()
|
|
1481
1580
|
|
|
1482
1581
|
for entity in query_shots:
|
|
1483
1582
|
shot = entity.serialize()
|
|
1484
|
-
full_name, _ = names_service.get_full_entity_name(shot["id"])
|
|
1583
|
+
full_name, _, _ = names_service.get_full_entity_name(shot["id"])
|
|
1485
1584
|
shot["full_name"] = full_name
|
|
1486
1585
|
shot["weight"] = 1
|
|
1487
1586
|
shots.append(shot)
|
|
@@ -1503,3 +1602,76 @@ def get_all_raw_shots():
|
|
|
1503
1602
|
"""
|
|
1504
1603
|
query = Entity.query.filter(Entity.entity_type_id == get_shot_type()["id"])
|
|
1505
1604
|
return query.all()
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
def set_frames_from_task_type_preview_files(
|
|
1608
|
+
project_id,
|
|
1609
|
+
task_type_id,
|
|
1610
|
+
episode_id=None,
|
|
1611
|
+
):
|
|
1612
|
+
from zou.app import db
|
|
1613
|
+
|
|
1614
|
+
shot_type = get_shot_type()
|
|
1615
|
+
Shot = aliased(Entity)
|
|
1616
|
+
Sequence = aliased(Entity)
|
|
1617
|
+
|
|
1618
|
+
if episode_id is not None:
|
|
1619
|
+
subquery = (
|
|
1620
|
+
db.session.query(
|
|
1621
|
+
Shot.id.label("entity_id"),
|
|
1622
|
+
func.max(PreviewFile.created_at).label("max_created_at"),
|
|
1623
|
+
)
|
|
1624
|
+
.join(Task, PreviewFile.task_id == Task.id)
|
|
1625
|
+
.join(Shot, Task.entity_id == Shot.id)
|
|
1626
|
+
.join(Sequence, Sequence.id == Shot.parent_id)
|
|
1627
|
+
.filter(Shot.project_id == project_id)
|
|
1628
|
+
.filter(Shot.entity_type_id == shot_type["id"])
|
|
1629
|
+
.filter(Task.task_type_id == task_type_id)
|
|
1630
|
+
.filter(Sequence.parent_id == episode_id)
|
|
1631
|
+
.group_by(Shot.id)
|
|
1632
|
+
.subquery()
|
|
1633
|
+
)
|
|
1634
|
+
else:
|
|
1635
|
+
subquery = (
|
|
1636
|
+
db.session.query(
|
|
1637
|
+
Shot.id.label("entity_id"),
|
|
1638
|
+
func.max(PreviewFile.created_at).label("max_created_at"),
|
|
1639
|
+
)
|
|
1640
|
+
.join(Task, PreviewFile.task_id == Task.id)
|
|
1641
|
+
.join(Shot, Task.entity_id == Shot.id)
|
|
1642
|
+
.filter(Shot.project_id == project_id)
|
|
1643
|
+
.filter(Shot.entity_type_id == shot_type["id"])
|
|
1644
|
+
.filter(Task.task_type_id == task_type_id)
|
|
1645
|
+
.group_by(Shot.id)
|
|
1646
|
+
.subquery()
|
|
1647
|
+
)
|
|
1648
|
+
|
|
1649
|
+
query = (
|
|
1650
|
+
db.session.query(Shot, PreviewFile.duration)
|
|
1651
|
+
.join(Task, Task.entity_id == Shot.id)
|
|
1652
|
+
.join(subquery, (Shot.id == subquery.c.entity_id))
|
|
1653
|
+
.join(
|
|
1654
|
+
PreviewFile,
|
|
1655
|
+
(PreviewFile.task_id == Task.id)
|
|
1656
|
+
& (PreviewFile.created_at == subquery.c.max_created_at),
|
|
1657
|
+
)
|
|
1658
|
+
.filter(Task.task_type_id == task_type_id)
|
|
1659
|
+
.filter(Shot.project_id == project_id)
|
|
1660
|
+
)
|
|
1661
|
+
|
|
1662
|
+
results = query.all()
|
|
1663
|
+
project = projects_service.get_project(project_id)
|
|
1664
|
+
updates = []
|
|
1665
|
+
for shot, preview_duration in results:
|
|
1666
|
+
nb_frames = round(preview_duration * float(project["fps"]))
|
|
1667
|
+
updates.append(
|
|
1668
|
+
{
|
|
1669
|
+
"id": shot.id,
|
|
1670
|
+
"nb_frames": nb_frames,
|
|
1671
|
+
}
|
|
1672
|
+
)
|
|
1673
|
+
clear_shot_cache(str(shot.id))
|
|
1674
|
+
|
|
1675
|
+
db.session.bulk_update_mappings(Shot, updates)
|
|
1676
|
+
db.session.commit()
|
|
1677
|
+
return updates
|