def update_assignment(self, updates, assignment, actioned_item, reassign,
                          already_completed, need_complete):
        # Update assignments, assignment history and publish planning
        # set the state to in progress if no item in the updates chain has ever been published
        updated = False
        if need_complete:
            updates['assigned_to'][
                'state'] = ASSIGNMENT_WORKFLOW_STATE.COMPLETED
        elif not already_completed:
            new_state = ASSIGNMENT_WORKFLOW_STATE.COMPLETED if \
                actioned_item.get(ITEM_STATE) in [CONTENT_STATE.PUBLISHED, CONTENT_STATE.CORRECTED] else \
                ASSIGNMENT_WORKFLOW_STATE.IN_PROGRESS
            updates['assigned_to']['state'] = get_next_assignment_status(
                updates, new_state)
            updated = True

        # on fulfiling the assignment the user is assigned the assignment, for add to planning it is not
        if reassign:
            user = get_user()
            if user and str(user.get(config.ID_FIELD)) != \
                    (assignment.get('assigned_to') or {}).get('user'):
                updates['assigned_to']['user'] = str(user.get(config.ID_FIELD))
                updated = True

            # if the item & assignment are'nt on the same desk, move the assignment to the item desk
            if (assignment.get('assigned_to') or {}).get('desk') != str(
                    actioned_item.get('task').get('desk')):
                updates['assigned_to']['desk'] = str(
                    actioned_item.get('task').get('desk'))
                updated = True

            # On a reassign if it was accepted clear the accept flag
            if assignment.get('accepted', False):
                updates['accepted'] = False
                updated = True

        if need_complete:
            get_resource_service('assignments_complete').update(
                assignment[config.ID_FIELD], updates, assignment)
        if updated:
            get_resource_service('assignments').patch(
                assignment[config.ID_FIELD], updates)
    def create(self, docs):
        ids = []
        archive_service = get_resource_service('archive')
        assignments_service = get_resource_service('assignments')
        for doc in docs:
            assignment = assignments_service.find_one(
                req=None, _id=doc.pop('assignment_id'))
            item = get_item_from_assignment(assignment,
                                            doc.pop('template_name', None))
            item[config.VERSION] = 1
            item.setdefault('type', 'text')
            item['assignment_id'] = assignment[config.ID_FIELD]

            if assignment.get('scheduled_update_id'):
                # get the latest archive item to be updated
                archive_item = self.get_latest_news_item_for_coverage(
                    assignment)

                if not archive_item:
                    raise SuperdeskApiError.badRequestError(
                        'Archive item not found to create a rewrite.')

                # create a rewrite
                request.view_args['original_id'] = archive_item.get(
                    config.ID_FIELD)
                ids = get_resource_service('archive_rewrite').post([{
                    'desk_id':
                    str(item.get('task').get('desk'))
                }])
                item = archive_service.find_one(_id=ids[0], req=None)
                item['task']['user'] = get_user_id()

                # link the rewrite
                get_resource_service('assignments_link').post([{
                    'assignment_id':
                    assignment[config.ID_FIELD],
                    'item_id':
                    ids[0],
                    'reassign':
                    True
                }])
            else:
                # create content
                ids = archive_service.post([item])
                insert_into_versions(doc=item)

                # create delivery references
                get_resource_service('delivery').post([{
                    'item_id':
                    item[config.ID_FIELD],
                    'assignment_id':
                    assignment[config.ID_FIELD],
                    'planning_id':
                    assignment['planning_item'],
                    'coverage_id':
                    assignment['coverage_item']
                }])

            updates = {'assigned_to': deepcopy(assignment.get('assigned_to'))}
            updates['assigned_to']['user'] = str(item.get('task').get('user'))
            updates['assigned_to']['desk'] = str(item.get('task').get('desk'))
            updates['assigned_to']['state'] = get_next_assignment_status(
                updates, ASSIGNMENT_WORKFLOW_STATE.IN_PROGRESS)
            updates['assigned_to']['assignor_user'] = str(
                item.get('task').get('user'))
            updates['assigned_to']['assigned_date_user'] = utcnow()

            if not assignment.get('scheduled_update_id'):
                # set the assignment to in progress
                assignments_service.patch(assignment[config.ID_FIELD], updates)
                assignments_service.publish_planning(
                    assignment['planning_item'])

            doc.update(item)
            ids.append(doc['_id'])

            # Send notification that the work has commenced to the user who assigned the task
            # Get the id of the user who assigned the task
            assignor = assignment.get('assigned_to', {}).get(
                'assignor_user',
                assignment.get('assigned_to', {}).get('assignor_desk'))

            if str(assignor) != str(item.get('task').get('user')):
                # Determine the display name of the assignee
                assigned_to_user = get_resource_service('users').find_one(
                    req=None, _id=str(item.get('task').get('user')))
                assignee = assigned_to_user.get(
                    'display_name') if assigned_to_user else 'Unknown'
                PlanningNotifications().notify_assignment(
                    target_desk=None,
                    target_user=assignor,
                    message='assignment_commenced_msg',
                    assignee=assignee,
                    coverage_type=get_coverage_type_name(item.get('type', '')),
                    slugline=item.get('slugline'),
                    omit_user=True,
                    assignment_id=assignment[config.ID_FIELD],
                    is_link=True,
                    no_email=True)
            # Save history
            get_resource_service('assignments_history').on_item_start_working(
                updates, assignment)

        return ids
    def update(self, id, updates, original):
        # if the completion is being done by an external application then ensure that it is not locked
        if 'proxy_user' in updates:
            if original.get('lock_user'):
                raise SuperdeskApiError.forbiddenError('Assignment is locked')
            user = updates.pop('proxy_user', None)
            proxy_user = True
        else:
            user = get_user(required=True).get(config.ID_FIELD, '')
            proxy_user = False
        session = get_auth().get(config.ID_FIELD, '')

        original_assigned_to = deepcopy(original).get('assigned_to')
        if not updates.get('assigned_to'):
            updates['assigned_to'] = {}
        original_assigned_to.update(updates['assigned_to'])
        updates['assigned_to'] = original_assigned_to

        assignments_service = get_resource_service('assignments')
        # If we are confirming availability, save the revert state for revert action
        text_assignment = assignments_service.is_text_assignment(original)
        if not text_assignment:
            updates['assigned_to']['revert_state'] = updates['assigned_to'][
                'state']

        updates['assigned_to']['state'] = get_next_assignment_status(
            updates, ASSIGNMENT_WORKFLOW_STATE.COMPLETED)

        remove_lock_information(updates)

        item = self.backend.update(self.datasource, id, updates, original)

        # publish the planning item
        assignments_service.publish_planning(original['planning_item'])

        # Save history if user initiates complete
        if text_assignment:
            get_resource_service('assignments_history').on_item_complete(
                updates, original)
        else:
            if proxy_user:
                updates['proxy_user'] = user
            get_resource_service(
                'assignments_history').on_item_confirm_availability(
                    updates, original)

        push_notification('assignments:completed',
                          item=str(original[config.ID_FIELD]),
                          planning=original.get('planning_item'),
                          assigned_user=(original.get('assigned_to')
                                         or {}).get('user'),
                          assigned_desk=(original.get('assigned_to')
                                         or {}).get('desk'),
                          assignment_state=ASSIGNMENT_WORKFLOW_STATE.COMPLETED,
                          user=str(user),
                          session=str(session),
                          coverage=original.get('coverage_item'))

        # Send notification that the work has been completed
        # Determine the display name of the assignee
        assigned_to_user = get_resource_service('users').find_one(req=None,
                                                                  _id=user)
        assignee = assigned_to_user.get(
            'display_name') if assigned_to_user else 'Unknown'
        target_user = original.get('assigned_to', {}).get('assignor_user')
        if target_user is None:
            target_user = original.get('assigned_to', {}).get('assignor_desk')
        PlanningNotifications().notify_assignment(
            target_user=target_user,
            message='assignment_fulfilled_msg',
            assignee=assignee,
            coverage_type=get_coverage_type_name(
                original.get('planning', {}).get('g2_content_type', '')),
            slugline=original.get('planning', {}).get('slugline'),
            omit_user=True,
            assignment_id=original[config.ID_FIELD],
            is_link=True,
            no_email=True)

        return item