예제 #1
0
    def save_template(self, file_handle, file_name):
        """ A new template document is added to our database.

        We ask for a file handle because we expect the file to
        come from the web server (that's the way cherrypy does it).

        :returns the doc id of the file
        """

        mainlog.debug(u"save_template(): fh:{} fn:{}".format(
            file_handle, file_name))

        document = TemplateDocument()
        document.filename = file_name
        document.upload_date = date.today()
        document.server_location = "DUMMY"
        document.file_size = 666

        session().add(document)
        session().flush()  # get an id

        document.server_location, document.file_size = self._copy_file_to_storage(
            file_handle, document.document_id, file_name)
        doc_id = document.document_id
        audit_trail_service.record("TEMPLATE_CREATED",
                                   "",
                                   document.document_id,
                                   commit=False)
        session().commit()

        mainlog.debug("Saved to template doc_id={}, bytes={}".format(
            doc_id, document.file_size))
        return doc_id
예제 #2
0
    def replace_template(self, template_id, file_handle, file_name):
        """ A new template document replaces an old one in our database.

        We ask for a file handle because we expect the file to
        come from the web server (that's the way cherrypy does it).
        """

        mainlog.debug(u"replace_template(): doc_id:{}, fh:{} fn:{}".format(
            template_id, file_handle, file_name))

        document = session().query(TemplateDocument).filter(
            TemplateDocument.template_document_id == template_id).one()
        document.filename = file_name
        document.upload_date = date.today()
        document.server_location = "DUMMY"
        document.file_size = 666

        document.server_location, document.file_size = self._copy_file_to_storage(
            file_handle, document.document_id, file_name)
        doc_id = document.document_id  # save for use after session's flushed
        audit_trail_service.record("TEMPLATE_REPLACED",
                                   "",
                                   document.document_id,
                                   commit=False)
        session().commit()

        mainlog.debug("Replaced template {}".format(doc_id))
        return doc_id
예제 #3
0
    def update_name_and_description(self, document_id: int, name: str,
                                    description: str):

        if not name:
            raise ServerException(ServerErrors.file_name_cannot_be_empty)
            # file_name_cannot_be_empty
            # raise Exception("Name cannot be empty")

        mainlog.debug('Renaming doc:{} to:{} with description:{}'.format(
            document_id, name, description))
        try:
            self._rename_file_in_storage(document_id, name)
        except Exception as ex:
            mainlog.error("Could not rename document {}".format(document_id))
            mainlog.exception(ex)

        doc = session().query(Document).filter(
            Document.document_id == document_id).one()
        doc.description = description or ""
        doc.filename = name
        audit_trail_service.record("DOCUMENT_RENAMED",
                                   "",
                                   document_id,
                                   commit=False)
        session().commit()
예제 #4
0
    def copy_template_to_document(self, template_id):
        tpl = session().query(TemplateDocument).filter(
            TemplateDocument.template_document_id == template_id).one()
        doc_id = None
        with open(tpl.server_location, 'rb') as f:
            doc_id = self.save(None, f, tpl.filename, tpl.description)

        audit_trail_service.record("TEMPLATE_INSTANCIATED",
                                   "",
                                   template_id,
                                   commit=False)
        session().commit()

        return doc_id
예제 #5
0
    def _set_order_state(self, order: Order, state):

        if state not in OrderStatusType:
            # This will catch None state as well
            raise Exception("The state {} is unknown".format(state))

        if state == OrderStatusType.preorder_sent and order.sent_as_preorder is None:
            # Arriving to OrderStatusType.preorder_sent state
            order.sent_as_preorder = central_clock.today()

        elif order.state == OrderStatusType.preorder_sent and state == OrderStatusType.preorder_definition:
            # The user probably wants to clear an error
            order.sent_as_preorder = None

        if state in (OrderStatusType.order_completed,
                     OrderStatusType.order_aborted):
            order.completed_date = central_clock.today()
        else:
            order.completed_date = None

        # Pay attention, the following assignments are not as simple
        # as they seem. That is, they'll trigger an update (of course).
        # Since there are constraints tying preorder_label, accounting_label
        # and state, one must be careful that they are updated all at once
        # in a single update statement. The following assignment on
        # accounting label is constructed so that SQLAlchemy produces
        # one sql update statement. See the doc at file:///C:/PORT-STC/opt/python/Doc/sqlalchemy/orm/session.html#embedding-sql-insert-update-expressions-into-a-flush
        # order.preorder_label = None

        if (state in
            (OrderStatusType.preorder_definition,
             OrderStatusType.preorder_sent)) and order.preorder_label is None:
            order.preorder_label = gaplessseq('preorder_id')
            mainlog.debug(
                "_set_order_state() setting order.preorder_label to {} 'cos sate is {}"
                .format(order.preorder_label, order.state))

        elif (state not in (OrderStatusType.preorder_definition,
                            OrderStatusType.preorder_sent, OrderStatusType.
                            order_aborted)) and order.accounting_label is None:
            order.accounting_label = gaplessseq('order_id')
            mainlog.debug(
                "_set_labels_for_state() setting order.accouting_label {} 'cos sate is {}"
                .format(order.accounting_label, state))

        order.state = state
        audit_trail_service.record("ORDER_STATE_CHANGED",
                                   "State transition to {}".format(state),
                                   order.order_id,
                                   commit=False)
예제 #6
0
    def save(self, document_id, file_handle, file_name, description):
        """ If document id is None (or 0), a new document is added to our database.
        Else an old one is overwritten.

        We ask for a file handle because we expect the file to
        come from the web server (that's the way cherrypy does it).
        """

        mainlog.debug(u"save(): id:{} fh:{} fn:{} d:{}".format(
            document_id, file_handle, file_name, description))

        c = all_non_relation_columns(Document)
        document = None
        if document_id:
            document = session().query(*c).filter(
                Document.document_id == document_id).one()
            session().commit()
        else:
            document = Document()
            session().add(document)

        document.filename = file_name
        document.upload_date = date.today()
        document.description = description or ""

        # I need the id to store on the file system.
        # But to get the server_location, I need to store on the filesystem
        # => catch 22

        document.server_location = "DUMMY"
        document.file_size = 666

        if not document.document_id:
            session().flush()  # get an id

        document.server_location, document.file_size = self._copy_file_to_storage(
            file_handle, document.document_id, file_name)
        doc_id = document.document_id
        audit_trail_service.record("DOCUMENT_CREATED",
                                   "",
                                   document.document_id,
                                   commit=False)
        session().commit()

        mainlog.debug("Saved to document {}".format(doc_id))
        return doc_id
예제 #7
0
    def transition_part_state(self, order_part: OrderPart, state):
        """ Transition an order part state, and apply all business decisions
        accordingly.

        :param order_part: An OrderPart (will usually be part of a sqla session)
        :param state: The new state.
        :return:
        """

        assert isinstance(order_part, OrderPart)
        from koi.datalayer.DeclEnumP3 import EnumSymbol
        assert isinstance(state, EnumSymbol)

        if state != order_part.state:

            mainlog.debug("transition_part_state : {} --> {}".format(
                order_part, state))
            if order_part.state and state not in self.order_part_possible_next_states(
                    order_part.state):
                raise DataException(
                    "Improper transition from state '{}' to state '{}'".format(
                        order_part.state, state),
                    DataException.IMPROPER_STATE_TRANSITION)

            mainlog.debug(u"Order part {} : transiion from {} -> {}".format(
                order_part.order_part_id, order_part.state, state))
            order_part.state = state

            # So that means that if the user changes a past part (say january)
            # from completed to aborted, then the changed part "moves" to
            # today (and thus may move from on GUI view to another)

            if order_part.state in (OrderPartStateType.completed,
                                    OrderPartStateType.aborted):
                order_part.completed_date = central_clock.today()
            else:
                order_part.completed_date = None

            audit_trail_service.record("UPDATE_ORDER_PART",
                                       "Transition to {} for {}:{}".format(
                                           state.description, order_part.label,
                                           order_part.description),
                                       order_part.order_part_id,
                                       commit=False)
        else:
            mainlog.debug("transition_part_state : nothing to do")
예제 #8
0
    def delete(self, document_id: int):
        # This is expected to work polymorphically on Documents' children.
        # So you can delete anything that inherits from Document.

        mainlog.debug("delete document id {}".format(document_id))

        doc = session().query(Document).filter(
            Document.document_id == document_id).one()

        self._remove_file_from_storage(doc.document_id)

        session().delete(
            doc
        )  # Cascade to order_part / order <-> document association table
        audit_trail_service.record("DOCUMENT_DELETED",
                                   "",
                                   document_id,
                                   commit=False)
        session().commit()
예제 #9
0
    def mark_as_non_conform(self, quality_event_dto, commit=True):
        part = self.dao.order_part_dao.find_by_id(
            quality_event_dto.order_part_id)

        # Create a non conformity event
        # self.dao.quality_dao.make(non_confomity_type, part.order_part_id, commit = False)

        self.dao.quality_dao.save_or_update(quality_event_dto)

        # Change the state of the order part
        self.transition_part_state(part, OrderPartStateType.non_conform)

        order_part = self.dao.order_part_dao.find_by_id(
            quality_event_dto.order_part_id)

        # will commit
        audit_trail_service.record(
            "UPDATE_ORDER_PART", "Non conformity : {} for {}:{}".format(
                quality_event_dto.kind.description, order_part.label,
                order_part.description), quality_event_dto.order_part_id)
예제 #10
0
    def _update_supply_order_parts(self, actions, supply_order):
        """ Pay attention ! This will update the action array to reflect the
        order part that were merged

        The object in the actions don't necessarily have to be
        SQLA mapped object, they can be frozen as well.
        """

        # FIXME replace supply_order by supply_order_id and merge
        # save supply order and update supply order parts

        # supply_order = session().query(SupplyOrder).filter(SupplyOrderPart.supply_order_id == supply_order_id).one()

        new_pos = 10000

        mainlog.debug("Reloading order parts into SQLA's session")

        for i in range(len(actions)):
            action_type, op, op_ndx = actions[i]
            if action_type == DBObjectActionTypes.TO_UPDATE:
                op = defrost_to_session(op, SupplyOrderPart)

            elif action_type == DBObjectActionTypes.UNCHANGED:

                # I don't use merge because merge will trigger
                # a copy of the attributes. Which will in
                # turn result in an UPDATE being performed.
                # And that is useless (since it is unchanged).
                # Moreover it makes testing a bit harder because
                # I have to think about the session to make
                # test cases.

                op = self._find_by_id(op.supply_order_part_id)

            elif action_type == DBObjectActionTypes.TO_CREATE:
                op = defrost_to_session(op, SupplyOrderPart)
                mainlog.debug("supply_order.supply_order_id = {}".format(
                    supply_order.supply_order_id))
                op.supply_order_id = supply_order.supply_order_id
                op.position = new_pos
                new_pos += 1

            elif action_type == DBObjectActionTypes.TO_DELETE:
                # Yes, we do need to merge the "TO_DELETE" ones. Because
                # SQLA will check against what it has in session.
                # SO if the part we want to destroy is already
                # in session and op is the same part but is not in
                # session, then SQLA will complain
                # op = session().merge(op)
                op = self._find_by_id(op.supply_order_part_id)
                supply_order.parts.remove(
                    op)  # We need the delete to cascade !
                # session().delete(op)

            actions[i] = (action_type, op, op_ndx)

        mainlog.debug("At this point, there are {} parts in the order".format(
            len(supply_order.parts)))

        # Remember that when doing flush, nothing guarantees
        # that the DB statements will be sent to the DB
        # in the order there were done in Python. SQLA
        # may reorder them at will.

        # Handles positions : order far away

        pos = 100000
        for action_type, op, op_ndx in actions:
            if action_type != DBObjectActionTypes.TO_DELETE:
                op.position = pos
                pos += 1

        session().flush()

        # Handles positions : bring back in place

        pos = 1
        for action_type, op, op_ndx in actions:
            if action_type != DBObjectActionTypes.TO_DELETE:
                # mainlog.debug(u"reposition {} {}".format(pos,op.description))
                op.position = pos
                pos += 1

        session().flush()
        self._recompute_position_labels(supply_order)

        session().commit()

        for action_type, op, op_ndx in actions:
            if action_type == DBObjectActionTypes.TO_CREATE:
                audit_trail_service.record("CREATE_SUPPLY_ORDER_PART", str(op),
                                           op.supply_order_part_id)
            if action_type == DBObjectActionTypes.TO_UPDATE:
                audit_trail_service.record("UPDATE_SUPPLY_ORDER_PART", str(op),
                                           op.supply_order_part_id)
            elif action_type == DBObjectActionTypes.TO_DELETE:
                # !!! Order id ! because order part id doesn't make sense after a delete :-)
                audit_trail_service.record("DELETE_SUPPLY_ORDER_PART", str(op),
                                           supply_order.supply_order_id)

        mainlog.debug(u"update_supply_order_parts -- done")

        return actions
예제 #11
0
 def test_add(self):
     audit_trail_service.record("CUSTOMER_EDIT", "name=Google", 123,
                                self.employee_id)