zou 0.20.38__py3-none-any.whl → 0.20.40__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/api.py +38 -43
- zou/app/blueprints/crud/__init__.py +10 -0
- zou/app/blueprints/crud/budget.py +21 -0
- zou/app/blueprints/crud/budget_entry.py +15 -0
- zou/app/blueprints/crud/plugin.py +13 -0
- zou/app/blueprints/crud/salary_scale.py +73 -0
- zou/app/blueprints/playlists/resources.py +15 -0
- zou/app/blueprints/projects/__init__.py +17 -0
- zou/app/blueprints/projects/resources.py +402 -7
- zou/app/blueprints/shots/resources.py +1 -0
- zou/app/mixin.py +12 -1
- zou/app/models/budget.py +39 -0
- zou/app/models/budget_entry.py +65 -0
- zou/app/models/person.py +17 -1
- zou/app/models/plugin.py +21 -0
- zou/app/models/salary_scale.py +28 -0
- zou/app/services/budget_service.py +195 -0
- zou/app/services/comments_service.py +1 -1
- zou/app/services/exception.py +8 -0
- zou/app/services/plugins_service.py +169 -0
- zou/app/services/user_service.py +1 -3
- zou/app/utils/commands.py +51 -1
- zou/app/utils/fields.py +10 -0
- zou/app/utils/plugins.py +88 -0
- zou/cli.py +169 -1
- zou/event_stream.py +23 -5
- zou/migrations/versions/2762a797f1f9_add_people_salary_information.py +52 -0
- zou/migrations/versions/45f739ef962a_add_people_salary_scale_table.py +70 -0
- zou/migrations/versions/4aab1f84ad72_introduce_plugin_table.py +68 -0
- zou/migrations/versions/7a16258f2fab_add_currency_field_to_budgets.py +33 -0
- zou/migrations/versions/83e2f33a9b14_add_project_bugdet_table.py +57 -0
- zou/migrations/versions/8ab98c178903_add_budget_entry_table.py +123 -0
- zou/migrations/versions/d25118cddcaa_modify_salary_scale_model.py +133 -0
- zou/plugin_template/__init__.py +39 -0
- zou/plugin_template/routes.py +6 -0
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/METADATA +7 -3
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/RECORD +42 -22
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/WHEEL +1 -1
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/entry_points.txt +0 -0
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/licenses/LICENSE +0 -0
- {zou-0.20.38.dist-info → zou-0.20.40.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ from flask_restful import Resource
|
|
|
2
2
|
from flask_jwt_extended import jwt_required
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
from zou.app.services import budget_service
|
|
5
6
|
from zou.app.mixin import ArgsMixin
|
|
6
7
|
from zou.app.services import (
|
|
7
8
|
projects_service,
|
|
@@ -165,7 +166,7 @@ class ProductionTeamRemoveResource(Resource):
|
|
|
165
166
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
166
167
|
responses:
|
|
167
168
|
204:
|
|
168
|
-
description:
|
|
169
|
+
description: Empty response
|
|
169
170
|
"""
|
|
170
171
|
user_service.check_manager_project_access(project_id)
|
|
171
172
|
projects_service.remove_team_member(project_id, person_id)
|
|
@@ -237,7 +238,7 @@ class ProductionAssetTypeRemoveResource(Resource):
|
|
|
237
238
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
238
239
|
responses:
|
|
239
240
|
204:
|
|
240
|
-
description:
|
|
241
|
+
description: Empty response
|
|
241
242
|
"""
|
|
242
243
|
user_service.check_manager_project_access(project_id)
|
|
243
244
|
projects_service.remove_asset_type_setting(project_id, asset_type_id)
|
|
@@ -343,7 +344,7 @@ class ProductionTaskTypeRemoveResource(Resource):
|
|
|
343
344
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
344
345
|
responses:
|
|
345
346
|
204:
|
|
346
|
-
description:
|
|
347
|
+
description: Empty response
|
|
347
348
|
"""
|
|
348
349
|
user_service.check_manager_project_access(project_id)
|
|
349
350
|
projects_service.remove_task_type_setting(project_id, task_type_id)
|
|
@@ -436,7 +437,7 @@ class ProductionTaskStatusRemoveResource(Resource):
|
|
|
436
437
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
437
438
|
responses:
|
|
438
439
|
204:
|
|
439
|
-
description:
|
|
440
|
+
description: Empty response
|
|
440
441
|
"""
|
|
441
442
|
user_service.check_manager_project_access(project_id)
|
|
442
443
|
projects_service.remove_task_status_setting(project_id, task_status_id)
|
|
@@ -529,7 +530,7 @@ class ProductionStatusAutomationRemoveResource(Resource):
|
|
|
529
530
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
530
531
|
responses:
|
|
531
532
|
204:
|
|
532
|
-
description:
|
|
533
|
+
description: Empty response
|
|
533
534
|
"""
|
|
534
535
|
user_service.check_manager_project_access(project_id)
|
|
535
536
|
projects_service.remove_status_automation_setting(
|
|
@@ -626,7 +627,7 @@ class ProductionPreviewBackgroundFileRemoveResource(Resource):
|
|
|
626
627
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
627
628
|
responses:
|
|
628
629
|
204:
|
|
629
|
-
description:
|
|
630
|
+
description: Empty response
|
|
630
631
|
"""
|
|
631
632
|
user_service.check_manager_project_access(project_id)
|
|
632
633
|
projects_service.remove_preview_background_file_setting(
|
|
@@ -864,7 +865,7 @@ class ProductionMetadataDescriptorResource(Resource, ArgsMixin):
|
|
|
864
865
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
865
866
|
responses:
|
|
866
867
|
204:
|
|
867
|
-
description:
|
|
868
|
+
description: Empty response
|
|
868
869
|
"""
|
|
869
870
|
user_service.check_all_departments_access(
|
|
870
871
|
project_id,
|
|
@@ -1092,3 +1093,397 @@ class ProductionSequencesScheduleItemsResource(Resource):
|
|
|
1092
1093
|
return schedule_service.get_sequences_schedule_items(
|
|
1093
1094
|
project_id, task_type_id
|
|
1094
1095
|
)
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
class ProductionBudgetsResource(Resource, ArgsMixin):
|
|
1099
|
+
|
|
1100
|
+
@jwt_required()
|
|
1101
|
+
def get(self, project_id):
|
|
1102
|
+
"""
|
|
1103
|
+
Retrieve budgets for given production
|
|
1104
|
+
---
|
|
1105
|
+
tags:
|
|
1106
|
+
- Projects
|
|
1107
|
+
parameters:
|
|
1108
|
+
- in: path
|
|
1109
|
+
name: project_id
|
|
1110
|
+
required: true
|
|
1111
|
+
type: string
|
|
1112
|
+
format: UUID
|
|
1113
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1114
|
+
responses:
|
|
1115
|
+
200:
|
|
1116
|
+
description: All budgets of given production
|
|
1117
|
+
"""
|
|
1118
|
+
user_service.check_manager_project_access(project_id)
|
|
1119
|
+
self.check_id_parameter(project_id)
|
|
1120
|
+
return budget_service.get_budgets(project_id)
|
|
1121
|
+
|
|
1122
|
+
@jwt_required()
|
|
1123
|
+
def post(self, project_id):
|
|
1124
|
+
"""
|
|
1125
|
+
Create a budget for given production.
|
|
1126
|
+
---
|
|
1127
|
+
tags:
|
|
1128
|
+
- Projects
|
|
1129
|
+
parameters:
|
|
1130
|
+
- in: path
|
|
1131
|
+
name: project_id
|
|
1132
|
+
required: true
|
|
1133
|
+
type: string
|
|
1134
|
+
format: UUID
|
|
1135
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1136
|
+
- in: formData
|
|
1137
|
+
name: name
|
|
1138
|
+
required: true
|
|
1139
|
+
type: string
|
|
1140
|
+
x-example: "New Budget"
|
|
1141
|
+
- in: formData
|
|
1142
|
+
name: currency
|
|
1143
|
+
required: false
|
|
1144
|
+
type: string
|
|
1145
|
+
x-example: "USD"
|
|
1146
|
+
responses:
|
|
1147
|
+
201:
|
|
1148
|
+
description: Budget created
|
|
1149
|
+
"""
|
|
1150
|
+
self.check_id_parameter(project_id)
|
|
1151
|
+
user_service.check_manager_project_access(project_id)
|
|
1152
|
+
data = self.get_args([("name", None, True), ("currency", None, False)])
|
|
1153
|
+
if data["currency"] is None:
|
|
1154
|
+
data["currency"] = "USD"
|
|
1155
|
+
return budget_service.create_budget(
|
|
1156
|
+
project_id, data["name"], data["currency"]
|
|
1157
|
+
)
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
class ProductionBudgetResource(Resource, ArgsMixin):
|
|
1161
|
+
"""
|
|
1162
|
+
Resource to retrieve a budget for given production.
|
|
1163
|
+
"""
|
|
1164
|
+
|
|
1165
|
+
@jwt_required()
|
|
1166
|
+
def get(self, project_id, budget_id):
|
|
1167
|
+
"""
|
|
1168
|
+
Retrieve a budget for given production
|
|
1169
|
+
---
|
|
1170
|
+
tags:
|
|
1171
|
+
- Projects
|
|
1172
|
+
parameters:
|
|
1173
|
+
- in: path
|
|
1174
|
+
name: project_id
|
|
1175
|
+
required: true
|
|
1176
|
+
type: string
|
|
1177
|
+
format: UUID
|
|
1178
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1179
|
+
- in: path
|
|
1180
|
+
name: budget_id
|
|
1181
|
+
required: true
|
|
1182
|
+
type: string
|
|
1183
|
+
format: UUID
|
|
1184
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1185
|
+
responses:
|
|
1186
|
+
200:
|
|
1187
|
+
description: Budget retrieved
|
|
1188
|
+
"""
|
|
1189
|
+
self.check_id_parameter(project_id)
|
|
1190
|
+
self.check_id_parameter(budget_id)
|
|
1191
|
+
user_service.check_manager_project_access(project_id)
|
|
1192
|
+
return budget_service.get_budget(budget_id)
|
|
1193
|
+
|
|
1194
|
+
@jwt_required()
|
|
1195
|
+
def put(self, project_id, budget_id):
|
|
1196
|
+
"""
|
|
1197
|
+
Update a budget name for given production
|
|
1198
|
+
---
|
|
1199
|
+
tags:
|
|
1200
|
+
- Projects
|
|
1201
|
+
parameters:
|
|
1202
|
+
- in: path
|
|
1203
|
+
name: project_id
|
|
1204
|
+
required: true
|
|
1205
|
+
type: string
|
|
1206
|
+
format: UUID
|
|
1207
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1208
|
+
- in: path
|
|
1209
|
+
name: budget_id
|
|
1210
|
+
required: true
|
|
1211
|
+
type: string
|
|
1212
|
+
format: UUID
|
|
1213
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1214
|
+
- in: formData
|
|
1215
|
+
name: name
|
|
1216
|
+
required: false
|
|
1217
|
+
type: string
|
|
1218
|
+
x-example: "New Budget"
|
|
1219
|
+
- in: formData
|
|
1220
|
+
name: currency
|
|
1221
|
+
required: false
|
|
1222
|
+
type: string
|
|
1223
|
+
x-example: "USD"
|
|
1224
|
+
responses:
|
|
1225
|
+
200:
|
|
1226
|
+
description: Budget updated
|
|
1227
|
+
"""
|
|
1228
|
+
self.check_id_parameter(project_id)
|
|
1229
|
+
self.check_id_parameter(budget_id)
|
|
1230
|
+
user_service.check_manager_project_access(project_id)
|
|
1231
|
+
data = self.get_args(
|
|
1232
|
+
[("name", None, False), ("currency", None, False)]
|
|
1233
|
+
)
|
|
1234
|
+
return budget_service.update_budget(
|
|
1235
|
+
budget_id, name=data["name"], currency=data["currency"]
|
|
1236
|
+
)
|
|
1237
|
+
|
|
1238
|
+
@jwt_required()
|
|
1239
|
+
def delete(self, project_id, budget_id):
|
|
1240
|
+
"""
|
|
1241
|
+
Delete a budget for given production
|
|
1242
|
+
---
|
|
1243
|
+
tags:
|
|
1244
|
+
- Projects
|
|
1245
|
+
parameters:
|
|
1246
|
+
- in: path
|
|
1247
|
+
name: project_id
|
|
1248
|
+
required: true
|
|
1249
|
+
type: string
|
|
1250
|
+
format: UUID
|
|
1251
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1252
|
+
- in: path
|
|
1253
|
+
name: budget_id
|
|
1254
|
+
required: true
|
|
1255
|
+
type: string
|
|
1256
|
+
format: UUID
|
|
1257
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1258
|
+
responses:
|
|
1259
|
+
204:
|
|
1260
|
+
description: Empty response
|
|
1261
|
+
"""
|
|
1262
|
+
self.check_id_parameter(project_id)
|
|
1263
|
+
self.check_id_parameter(budget_id)
|
|
1264
|
+
user_service.check_manager_project_access(project_id)
|
|
1265
|
+
budget_service.delete_budget(budget_id)
|
|
1266
|
+
return "", 204
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
class ProductionBudgetEntriesResource(Resource, ArgsMixin):
|
|
1270
|
+
|
|
1271
|
+
@jwt_required()
|
|
1272
|
+
def get(self, project_id, budget_id):
|
|
1273
|
+
"""
|
|
1274
|
+
Retrieve budget entries for given production
|
|
1275
|
+
---
|
|
1276
|
+
tags:
|
|
1277
|
+
- Projects
|
|
1278
|
+
parameters:
|
|
1279
|
+
- in: path
|
|
1280
|
+
name: project_id
|
|
1281
|
+
required: true
|
|
1282
|
+
type: string
|
|
1283
|
+
format: UUID
|
|
1284
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1285
|
+
- in: path
|
|
1286
|
+
name: budget_id
|
|
1287
|
+
required: true
|
|
1288
|
+
type: string
|
|
1289
|
+
format: UUID
|
|
1290
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1291
|
+
responses:
|
|
1292
|
+
200:
|
|
1293
|
+
description: All budget entries of given production and budget
|
|
1294
|
+
"""
|
|
1295
|
+
self.check_id_parameter(project_id)
|
|
1296
|
+
self.check_id_parameter(budget_id)
|
|
1297
|
+
user_service.check_manager_project_access(project_id)
|
|
1298
|
+
return budget_service.get_budget_entries(budget_id)
|
|
1299
|
+
|
|
1300
|
+
@jwt_required()
|
|
1301
|
+
def post(self, project_id, budget_id):
|
|
1302
|
+
"""
|
|
1303
|
+
Create a budget entry for given production and budget
|
|
1304
|
+
"""
|
|
1305
|
+
self.check_id_parameter(project_id)
|
|
1306
|
+
self.check_id_parameter(budget_id)
|
|
1307
|
+
user_service.check_manager_project_access(project_id)
|
|
1308
|
+
data = self.get_args(
|
|
1309
|
+
[
|
|
1310
|
+
("department_id", None, True),
|
|
1311
|
+
("person_id", None, False),
|
|
1312
|
+
("start_date", None, False),
|
|
1313
|
+
("months_duration", None, False),
|
|
1314
|
+
("daily_salary", None, False),
|
|
1315
|
+
("position", None, False),
|
|
1316
|
+
("seniority", None, False),
|
|
1317
|
+
]
|
|
1318
|
+
)
|
|
1319
|
+
return budget_service.create_budget_entry(
|
|
1320
|
+
budget_id,
|
|
1321
|
+
data["department_id"],
|
|
1322
|
+
data["start_date"],
|
|
1323
|
+
data["months_duration"],
|
|
1324
|
+
data["daily_salary"],
|
|
1325
|
+
data["position"],
|
|
1326
|
+
data["seniority"],
|
|
1327
|
+
person_id=data["person_id"],
|
|
1328
|
+
)
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
class ProductionBudgetEntryResource(Resource, ArgsMixin):
|
|
1332
|
+
|
|
1333
|
+
@jwt_required()
|
|
1334
|
+
def get(self, project_id, budget_id, entry_id):
|
|
1335
|
+
"""
|
|
1336
|
+
Retrieve a budget entry for given production and budget
|
|
1337
|
+
---
|
|
1338
|
+
tags:
|
|
1339
|
+
- Projects
|
|
1340
|
+
parameters:
|
|
1341
|
+
- in: path
|
|
1342
|
+
name: project_id
|
|
1343
|
+
required: true
|
|
1344
|
+
type: string
|
|
1345
|
+
format: UUID
|
|
1346
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1347
|
+
- in: path
|
|
1348
|
+
name: budget_id
|
|
1349
|
+
required: true
|
|
1350
|
+
type: string
|
|
1351
|
+
format: UUID
|
|
1352
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1353
|
+
- in: path
|
|
1354
|
+
name: entry_id
|
|
1355
|
+
required: true
|
|
1356
|
+
type: string
|
|
1357
|
+
format: UUID
|
|
1358
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1359
|
+
responses:
|
|
1360
|
+
200:
|
|
1361
|
+
description: Budget entry retrieved
|
|
1362
|
+
"""
|
|
1363
|
+
user_service.check_manager_project_access(project_id)
|
|
1364
|
+
self.check_id_parameter(project_id)
|
|
1365
|
+
self.check_id_parameter(budget_id)
|
|
1366
|
+
self.check_id_parameter(entry_id)
|
|
1367
|
+
return budget_service.get_budget_entry(entry_id)
|
|
1368
|
+
|
|
1369
|
+
@jwt_required()
|
|
1370
|
+
def put(self, project_id, budget_id, entry_id):
|
|
1371
|
+
"""
|
|
1372
|
+
Update a budget entry for given production and budget
|
|
1373
|
+
---
|
|
1374
|
+
tags:
|
|
1375
|
+
- Projects
|
|
1376
|
+
parameters:
|
|
1377
|
+
- in: path
|
|
1378
|
+
name: project_id
|
|
1379
|
+
required: true
|
|
1380
|
+
type: string
|
|
1381
|
+
format: UUID
|
|
1382
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1383
|
+
- in: path
|
|
1384
|
+
name: budget_id
|
|
1385
|
+
required: true
|
|
1386
|
+
type: string
|
|
1387
|
+
format: UUID
|
|
1388
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1389
|
+
- in: path
|
|
1390
|
+
name: entry_id
|
|
1391
|
+
required: true
|
|
1392
|
+
type: string
|
|
1393
|
+
format: UUID
|
|
1394
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1395
|
+
- in: formData
|
|
1396
|
+
name: department_id
|
|
1397
|
+
required: false
|
|
1398
|
+
type: string
|
|
1399
|
+
format: UUID
|
|
1400
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1401
|
+
- in: formData
|
|
1402
|
+
name: person_id
|
|
1403
|
+
required: false
|
|
1404
|
+
type: string
|
|
1405
|
+
format: UUID
|
|
1406
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1407
|
+
- in: formData
|
|
1408
|
+
name: start_date
|
|
1409
|
+
required: false
|
|
1410
|
+
type: string
|
|
1411
|
+
format: date
|
|
1412
|
+
x-example: 2025-01-01
|
|
1413
|
+
- in: formData
|
|
1414
|
+
name: months_duration
|
|
1415
|
+
required: false
|
|
1416
|
+
type: integer
|
|
1417
|
+
x-example: 12
|
|
1418
|
+
- in: formData
|
|
1419
|
+
name: daily_salary
|
|
1420
|
+
required: false
|
|
1421
|
+
type: float
|
|
1422
|
+
x-example: 100.00
|
|
1423
|
+
- in: formData
|
|
1424
|
+
name: position
|
|
1425
|
+
required: false
|
|
1426
|
+
type: string
|
|
1427
|
+
x-example: "Artist"
|
|
1428
|
+
- in: formData
|
|
1429
|
+
name: seniority
|
|
1430
|
+
required: false
|
|
1431
|
+
type: string
|
|
1432
|
+
x-example: "Mid"
|
|
1433
|
+
responses:
|
|
1434
|
+
200:
|
|
1435
|
+
description: Budget entry updated
|
|
1436
|
+
"""
|
|
1437
|
+
user_service.check_manager_project_access(project_id)
|
|
1438
|
+
self.check_id_parameter(project_id)
|
|
1439
|
+
self.check_id_parameter(budget_id)
|
|
1440
|
+
self.check_id_parameter(entry_id)
|
|
1441
|
+
data = self.get_args(
|
|
1442
|
+
[
|
|
1443
|
+
("department_id", None, False),
|
|
1444
|
+
("person_id", None, False),
|
|
1445
|
+
("start_date", None, False),
|
|
1446
|
+
("months_duration", None, False),
|
|
1447
|
+
("daily_salary", None, False),
|
|
1448
|
+
("position", None, False),
|
|
1449
|
+
("seniority", None, False),
|
|
1450
|
+
]
|
|
1451
|
+
)
|
|
1452
|
+
return budget_service.update_budget_entry(entry_id, data)
|
|
1453
|
+
|
|
1454
|
+
@jwt_required()
|
|
1455
|
+
def delete(self, project_id, budget_id, entry_id):
|
|
1456
|
+
"""
|
|
1457
|
+
Delete a budget entry for given production and budget.
|
|
1458
|
+
---
|
|
1459
|
+
tags:
|
|
1460
|
+
- Projects
|
|
1461
|
+
parameters:
|
|
1462
|
+
- in: path
|
|
1463
|
+
name: project_id
|
|
1464
|
+
required: true
|
|
1465
|
+
type: string
|
|
1466
|
+
format: UUID
|
|
1467
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1468
|
+
- in: path
|
|
1469
|
+
name: budget_id
|
|
1470
|
+
required: true
|
|
1471
|
+
type: string
|
|
1472
|
+
format: UUID
|
|
1473
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1474
|
+
- in: path
|
|
1475
|
+
name: entry_id
|
|
1476
|
+
required: true
|
|
1477
|
+
type: string
|
|
1478
|
+
format: UUID
|
|
1479
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1480
|
+
responses:
|
|
1481
|
+
204:
|
|
1482
|
+
description: empty response
|
|
1483
|
+
"""
|
|
1484
|
+
self.check_id_parameter(project_id)
|
|
1485
|
+
self.check_id_parameter(budget_id)
|
|
1486
|
+
self.check_id_parameter(entry_id)
|
|
1487
|
+
user_service.check_manager_project_access(project_id)
|
|
1488
|
+
budget_service.delete_budget_entry(entry_id)
|
|
1489
|
+
return "", 204
|
zou/app/mixin.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from flask_restful import reqparse
|
|
2
2
|
from flask import request
|
|
3
3
|
|
|
4
|
-
from zou.app.utils import date_helpers
|
|
4
|
+
from zou.app.utils import date_helpers, fields
|
|
5
5
|
from zou.app.services.exception import WrongParameterException
|
|
6
6
|
|
|
7
7
|
|
|
@@ -11,6 +11,9 @@ class ArgsMixin(object):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
def get_args(self, descriptors, location=None):
|
|
14
|
+
"""
|
|
15
|
+
Retrieve arguments from GET or POST queries.
|
|
16
|
+
"""
|
|
14
17
|
parser = reqparse.RequestParser()
|
|
15
18
|
if location is None:
|
|
16
19
|
location = ["values", "json"] if request.is_json else ["values"]
|
|
@@ -157,3 +160,11 @@ class ArgsMixin(object):
|
|
|
157
160
|
"Expected format: 2020-01-05T13:23:10 or 2020-01-05"
|
|
158
161
|
)
|
|
159
162
|
return date
|
|
163
|
+
|
|
164
|
+
def check_id_parameter(self, uuid):
|
|
165
|
+
"""
|
|
166
|
+
Check if the given UUID is valid.
|
|
167
|
+
"""
|
|
168
|
+
if not fields.is_valid_id(uuid):
|
|
169
|
+
raise WrongParameterException("Wrong UUID format.")
|
|
170
|
+
return True
|
zou/app/models/budget.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from sqlalchemy_utils import UUIDType
|
|
2
|
+
|
|
3
|
+
from zou.app import db
|
|
4
|
+
from zou.app.models.serializer import SerializerMixin
|
|
5
|
+
from zou.app.models.base import BaseMixin
|
|
6
|
+
from zou.app.utils import fields
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Budget(db.Model, BaseMixin, SerializerMixin):
|
|
10
|
+
"""
|
|
11
|
+
Budget quote for a project. It's a base object where budget entries
|
|
12
|
+
are linked to.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
project_id = db.Column(
|
|
16
|
+
UUIDType(binary=False), db.ForeignKey("project.id"), index=True
|
|
17
|
+
)
|
|
18
|
+
revision = db.Column(db.Integer, nullable=False, default=1)
|
|
19
|
+
name = db.Column(db.String(255), nullable=False)
|
|
20
|
+
currency = db.Column(db.String(3))
|
|
21
|
+
|
|
22
|
+
def __repr__(self):
|
|
23
|
+
return "<Budget of %s - %d %s %s>" % (
|
|
24
|
+
self.project_id,
|
|
25
|
+
self.revision,
|
|
26
|
+
self.name,
|
|
27
|
+
self.id,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def present(self):
|
|
31
|
+
return fields.serialize_dict(
|
|
32
|
+
{
|
|
33
|
+
"id": self.id,
|
|
34
|
+
"project_id": self.project_id,
|
|
35
|
+
"revision": self.revision,
|
|
36
|
+
"name": self.name,
|
|
37
|
+
"currency": self.currency,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from sqlalchemy_utils import (
|
|
2
|
+
UUIDType,
|
|
3
|
+
ChoiceType,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
from zou.app import db
|
|
7
|
+
from zou.app.models.serializer import SerializerMixin
|
|
8
|
+
from zou.app.models.base import BaseMixin
|
|
9
|
+
from zou.app.utils import fields
|
|
10
|
+
|
|
11
|
+
from zou.app.models.person import POSITION_TYPES, SENIORITY_TYPES
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BudgetEntry(db.Model, BaseMixin, SerializerMixin):
|
|
15
|
+
"""
|
|
16
|
+
Budget entry for a budget. It stores the information about a person
|
|
17
|
+
(present or not) salary for a given department.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
budget_id = db.Column(
|
|
21
|
+
UUIDType(binary=False),
|
|
22
|
+
db.ForeignKey("budget.id"),
|
|
23
|
+
index=True,
|
|
24
|
+
nullable=False,
|
|
25
|
+
)
|
|
26
|
+
department_id = db.Column(
|
|
27
|
+
UUIDType(binary=False),
|
|
28
|
+
db.ForeignKey("department.id"),
|
|
29
|
+
index=True,
|
|
30
|
+
nullable=False,
|
|
31
|
+
)
|
|
32
|
+
person_id = db.Column(
|
|
33
|
+
UUIDType(binary=False),
|
|
34
|
+
db.ForeignKey("person.id"),
|
|
35
|
+
index=True,
|
|
36
|
+
nullable=True,
|
|
37
|
+
)
|
|
38
|
+
start_date = db.Column(db.Date, nullable=False)
|
|
39
|
+
months_duration = db.Column(db.Integer, nullable=False)
|
|
40
|
+
daily_salary = db.Column(db.Float, nullable=False)
|
|
41
|
+
position = db.Column(ChoiceType(POSITION_TYPES), default="artist")
|
|
42
|
+
seniority = db.Column(ChoiceType(SENIORITY_TYPES), default="mid")
|
|
43
|
+
|
|
44
|
+
def __repr__(self):
|
|
45
|
+
return "<BudgetEntry of %s - %d %s %s>" % (
|
|
46
|
+
self.budget_id,
|
|
47
|
+
self.department_id,
|
|
48
|
+
self.person_id,
|
|
49
|
+
self.start_date,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def present(self):
|
|
53
|
+
return fields.serialize_dict(
|
|
54
|
+
{
|
|
55
|
+
"id": self.id,
|
|
56
|
+
"budget_id": self.budget_id,
|
|
57
|
+
"department_id": self.department_id,
|
|
58
|
+
"person_id": self.person_id,
|
|
59
|
+
"start_date": self.start_date,
|
|
60
|
+
"months_duration": self.months_duration,
|
|
61
|
+
"daily_salary": self.daily_salary,
|
|
62
|
+
"position": self.position,
|
|
63
|
+
"seniority": self.seniority,
|
|
64
|
+
}
|
|
65
|
+
)
|
zou/app/models/person.py
CHANGED
|
@@ -13,8 +13,8 @@ from pytz import timezone as pytz_timezone
|
|
|
13
13
|
from babel import Locale
|
|
14
14
|
|
|
15
15
|
from zou.app.models.serializer import SerializerMixin
|
|
16
|
-
from zou.app.models.base import BaseMixin
|
|
17
16
|
from zou.app.models.department import Department
|
|
17
|
+
from zou.app.models.base import BaseMixin
|
|
18
18
|
from zou.app import config, db
|
|
19
19
|
|
|
20
20
|
|
|
@@ -42,6 +42,18 @@ ROLE_TYPES = [
|
|
|
42
42
|
("vendor", "Vendor"),
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
+
POSITION_TYPES = [
|
|
46
|
+
("supervisor", "Supervisor"),
|
|
47
|
+
("lead", "Lead"),
|
|
48
|
+
("artist", "Artist"),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
SENIORITY_TYPES = [
|
|
52
|
+
("senior", "Senior"),
|
|
53
|
+
("mid", "Mid"),
|
|
54
|
+
("junior", "Junior"),
|
|
55
|
+
]
|
|
56
|
+
|
|
45
57
|
|
|
46
58
|
class DepartmentLink(db.Model):
|
|
47
59
|
__tablename__ = "department_link"
|
|
@@ -107,6 +119,10 @@ class Person(db.Model, BaseMixin, SerializerMixin):
|
|
|
107
119
|
locale = db.Column(LocaleType, default=Locale(config.DEFAULT_LOCALE))
|
|
108
120
|
data = db.Column(JSONB)
|
|
109
121
|
role = db.Column(ChoiceType(ROLE_TYPES), default="user", nullable=False)
|
|
122
|
+
position = db.Column(ChoiceType(POSITION_TYPES), default="artist")
|
|
123
|
+
seniority = db.Column(ChoiceType(SENIORITY_TYPES), default="mid")
|
|
124
|
+
daily_salary = db.Column(db.Integer, default=0)
|
|
125
|
+
|
|
110
126
|
has_avatar = db.Column(db.Boolean(), default=False)
|
|
111
127
|
|
|
112
128
|
notifications_enabled = db.Column(db.Boolean(), default=False)
|
zou/app/models/plugin.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from zou.app import db
|
|
2
|
+
from zou.app.models.serializer import SerializerMixin
|
|
3
|
+
from zou.app.models.base import BaseMixin
|
|
4
|
+
from sqlalchemy_utils import EmailType, URLType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Plugin(db.Model, BaseMixin, SerializerMixin):
|
|
8
|
+
"""
|
|
9
|
+
Describe a plugin.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
plugin_id = db.Column(
|
|
13
|
+
db.String(80), unique=True, nullable=False, index=True
|
|
14
|
+
)
|
|
15
|
+
name = db.Column(db.String(80), nullable=False, index=True)
|
|
16
|
+
description = db.Column(db.Text())
|
|
17
|
+
version = db.Column(db.String(50), nullable=False)
|
|
18
|
+
maintainer_name = db.Column(db.String(200), nullable=False)
|
|
19
|
+
maintainer_email = db.Column(EmailType)
|
|
20
|
+
website = db.Column(URLType)
|
|
21
|
+
license = db.Column(db.String(80), nullable=False)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from sqlalchemy_utils import UUIDType
|
|
2
|
+
from sqlalchemy_utils import ChoiceType
|
|
3
|
+
|
|
4
|
+
from zou.app.models.person import POSITION_TYPES, SENIORITY_TYPES
|
|
5
|
+
|
|
6
|
+
from zou.app import db
|
|
7
|
+
from zou.app.models.serializer import SerializerMixin
|
|
8
|
+
from zou.app.models.base import BaseMixin
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SalaryScale(db.Model, BaseMixin, SerializerMixin):
|
|
12
|
+
"""
|
|
13
|
+
Model to represent a salary scale tied to a department.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
department_id = db.Column(
|
|
17
|
+
UUIDType(binary=False),
|
|
18
|
+
db.ForeignKey("department.id"),
|
|
19
|
+
index=True,
|
|
20
|
+
nullable=False,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
position = db.Column(ChoiceType(POSITION_TYPES), default="artist")
|
|
24
|
+
seniority = db.Column(ChoiceType(SENIORITY_TYPES), default="mid")
|
|
25
|
+
salary = db.Column(db.Integer, nullable=False, default=0)
|
|
26
|
+
|
|
27
|
+
def present(self):
|
|
28
|
+
return self.serialize()
|