示例#1
0
    def _analyse_operation_non_imputable(self, operation_id):
        c = session().query(Operation.operation_id,
                            OperationDefinition.imputable,
                            OperationDefinition.short_id.label("operation_definition_short_id"),
                            OperationDefinition.on_operation,
                            Order.accounting_label.label("order_accounting_label"),
                            OrderPart.label.label("order_part_label"),
                            OrderPart.state.label("order_part_state")).\
            join(ProductionFile).\
            join(OrderPart).\
            join(Order).\
            join(OperationDefinition, OperationDefinition.operation_definition_id == Operation.operation_definition_id).\
            filter(Operation.operation_id == operation_id).first()

        if not c:
            raise ServerException(ServerErrors.operation_unknown, operation_id)
        elif not c.imputable:
            raise ServerException(
                ServerErrors.operation_definition_not_imputable,
                c.operation_definition_short_id)
        elif c.order_part_state != OrderStatusType.order_ready_for_production:
            raise ServerException(
                ServerErrors.order_part_not_in_production_unknown,
                "{}{}".format(c.order_accounting_label, c.order_part_label
                              or ""))
        else:
            raise ServerException(
                ServerErrors.general_failure,
                "This operation is imputable but I expectd it's not. Contact support !"
            )
示例#2
0
    def get_operation_information(self, employee_id: int, operation_id: int):
        """ Retrieve information about an operation.
        The operation is meant to be imputable.

        Returns a tuple :
        * operation
        * machines : machines available for the operation
        * next_action (if it was computable)
        * colleagues : a list of person working on the operation

        FIXME That is a problem : if the operation is not imputable, one
        should still be able to report an "end of task" (but no "start task")
        """

        try:
            o, m, next_action_kind, colleagues = dao.operation_dao.find_by_operation_id_frozen(
                employee_id, operation_id)
        except Exception as ex:
            mainlog.exception(ex)
            raise ServerException(ServerErrors.operation_unknown, operation_id)

        if o.imputable:
            # Ouch! I have to convert the colleagues to an array of tuple
            # because the colleagues are represented in a dict with keys which
            # are integers. Unfortunately, json converts those key to strings...

            return o, m, next_action_kind, colleagues

        else:
            self._analyse_operation_non_imputable(operation_id)
            raise ServerException(ServerErrors.operation_non_imputable,
                                  operation_id, o.order_part_identifier)
示例#3
0
    def _recordTaskOnOperation(self, operation_id, machine_id):
        """ Create a task for reporting time on a "task on operation"
        with machine_id and operation_id
        """

        mainlog.debug("*** " * 100)
        mainlog.debug(
            "_recordTaskOnOperation operation_id={}, machine_id={}".format(
                operation_id, machine_id))

        # First we locate the operation and check if one can record time on it.

        q = session().query(Operation.operation_id,
                            Order.accounting_label.label("order_accounting_label"),
                            OrderPart.label.label("order_part_label"),
                            OrderPart.description.label('order_part_description'),
                            Customer.fullname.label('customer_name'),
                            OperationDefinition.short_id.label("operation_definition_short_id"),
                            TaskOnOperation.task_id,
                            and_(OperationDefinition.imputable == True,
                                 OperationDefinition.on_operation == True,
                                 Order.state == OrderStatusType.order_ready_for_production).label("imputable"),
                            TaskOnOperation.active.label("task_active"),
                            Operation.description.label("operation_description"),
                            Operation.position.label("operation_position"))\
                     .join(ProductionFile).join(OrderPart).join(Order).outerjoin(TaskOnOperation,TaskOnOperation.operation_id == Operation.operation_id).join(OperationDefinition, OperationDefinition.operation_definition_id == Operation.operation_definition_id).join(Customer,Order.customer_id == Customer.customer_id).options(lazyload('*')).filter(Operation.operation_id == operation_id)

        row = q.first()

        if row is None:
            self._analyse_operation_non_imputable(operation_id)
            raise ServerException(ServerErrors.operation_non_imputable,
                                  operation_id)

        h = row._asdict()  # SQLA KeyedTupe

        h['task_type'] = 'TaskOnOperation'
        h['order_part_label'] = str(row[1]) + (row[2] or "-")

        if row.imputable:
            task_id = row.task_id
            if task_id is None:
                task_id = dao.task_dao.create_task_on_operation(
                    operation_id, machine_id).task_id

            elif not row.task_active:
                raise ServerException(ServerErrors.task_not_imputable, task_id)

            return task_id, h
        else:
            raise ServerException(
                ServerErrors.operation_non_imputable,
                u"'{} {}'".format((row.operation_definition_short_id or ""),
                                  (row.operation_description or "")),
                str(row.order_accounting_label) +
                (row.order_part_label or '-'))
示例#4
0
    def _figure_task_for_operation_and_machine(self, operation_id, machine_id):
        # FIXME Same as TaskDAO.get_task_for_operation_and_machine

        operation = self._load_operation_and_task_data(operation_id,
                                                       machine_id)
        task_id = operation.task_id

        # Check if the pointage has to be recorded on a machine too.

        machine_ids = [
            m.machine_id
            for m in machine_service.find_machines_for_operation_definition(
                operation.operation_definition_id)
        ]

        mainlog.debug("Authorized machine id's are : {}; you gave {}".format(
            machine_ids, machine_id))
        if not machine_id and machine_ids:
            raise ServerException(
                ServerErrors.machine_not_compatible_with_operation, machine_id,
                str(machine_ids))
        elif machine_id and machine_id not in machine_ids:
            raise ServerException(
                ServerErrors.machine_not_compatible_with_operation, machine_id,
                str(machine_ids))

        if operation.imputable:

            # Make sure a taks is tied to the operation/machine

            if operation.task_id is None:

                mainlog.debug(
                    "_make_task_for_operation_and_machine : create_task_on_operation"
                )
                task_id = dao.task_dao.create_task_on_operation(
                    operation_id, machine_id).task_id

            elif not operation.task_active:
                raise ServerException(ServerErrors.task_not_imputable, task_id)
        else:
            raise ServerException(
                ServerErrors.operation_non_imputable, u"'{} {}'".format(
                    (operation.operation_definition_short_id or ""),
                    (operation.operation_description or "")),
                str(operation.order_accounting_label) +
                (operation.order_part_label or '-'))

        return task_id
示例#5
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()
示例#6
0
    def find_machine_by_id(self, machine_id):
        if self._cache_by_id == None:
            self._reset_cache()

        if machine_id in self._cache_by_id:
            return self._cache_by_id[machine_id]
        else:
            raise ServerException(ServerErrors.unknown_machine, machine_id)
示例#7
0
    def set_event_on_days(self, day_event: DayEvent, days_duration: list):
        """ Set an event on several days each time with a specific duration.

        :param day_event:
        :param days_duration: An array of pairs. Each pair is (date, duration). Each date
         must be unique.
        :return:
        """

        day_max = date(1980, 1, 1)
        day_min = date(2050, 12, 31)

        mainlog.debug("set_event_on_days")
        mainlog.debug(days_duration)

        for day, duration in days_duration:
            day_min = min(day_min, day)
            day_max = max(day_max, day)

        db_events = session().query(DayEvent).filter(
            and_(DayEvent.employee_id == day_event.employee_id,
                 DayEvent.event_type == day_event.event_type,
                 DayEvent.date.between(day_min, day_max))).all()

        db_events_dates = dict(zip([e.date for e in db_events], db_events))

        other_db_events = session().query(DayEvent.date,
                                          func.sum(DayEvent.duration).label("duration_sum")).\
            filter( and_( DayEvent.employee_id == day_event.employee_id,
                          DayEvent.event_type != day_event.event_type,
                          DayEvent.date.between(day_min, day_max))).\
            group_by(DayEvent.date).all()

        other_db_events_dates = dict([(e.date, e.duration_sum)
                                      for e in other_db_events])

        for day, duration in days_duration:
            if day in other_db_events_dates and other_db_events_dates[
                    day] + duration > 1:
                raise ServerException(ServerErrors.too_much_off_time_on_a_day,
                                      date_to_dmy(day))

            if day in db_events_dates:
                # Replace the old duration
                db_event = db_events_dates[day]
                db_event.duration = duration
            else:
                nu_event = DayEvent()
                nu_event.date = day
                nu_event.duration = duration
                nu_event.event_type = day_event.event_type
                nu_event.employee_id = day_event.employee_id
                session().add(nu_event)

        session().commit()
示例#8
0
    def record_pointage_on_unbillable(self, operation_definition_id: int,
                                      employee_id: int, action_time: datetime,
                                      location: str,
                                      action_kind: TaskActionReportType):

        mainlog.debug("record_pointage_on_unbillable ")

        opdef = dao.operation_definition_dao.find_by_id_frozen(
            operation_definition_id, commit=False, resilient=True)

        if not opdef:
            raise ServerException(ServerErrors.operation_definition_unknown,
                                  operation_definition_id)
        elif not opdef.imputable:
            raise ServerException(
                ServerErrors.operation_definition_not_imputable,
                opdef.short_id)

        task_id = dao.task_dao._get_task_for_non_billable(
            operation_definition_id)
        self._recordActionOnWorkTask(task_id, employee_id, action_time,
                                     location, action_kind)
示例#9
0
    def _barcodeToTask(self, barcode, additional_data):
        data = None
        try:
            data = BarCodeIdentifier.barcode_to_id(barcode)
        except Exception as ex:
            raise ServerException(ServerErrors.barcode_syntax_invalid, barcode)

        if data[0] == Operation:
            operation_id = data[1]
            machine_id = additional_data
            task_id, h = self._recordTaskOnOperation(operation_id, machine_id)
            return task_id, h

        elif data[0] == OperationDefinition:
            operation_definition_id = data[1]
            task_id, h = self._recordTaskOnNonBillable(operation_definition_id)
            return task_id, h

        elif data[0] == Order and data[1] == OperationDefinition:
            order_id = data[2]
            operation_definition_id = data[3]
            task_id, h = self._recordTaskOnOrder(order_id,
                                                 operation_definition_id)
            # self.dao.task_dao.task_for_order(order_id,operation_definition_id)
            return task_id, h

        elif data[0] in (TaskActionReportType.day_in,
                         TaskActionReportType.day_out):
            task_id = dao.task_action_report_dao.presence_task().task_id
            h = dict()
            h['task_type'] = 'TaskForPresence'
            h['action_kind'] = data[0]

            return task_id, h

        else:
            raise ServerException(ServerErrors.barcode_invalid, barcode)
示例#10
0
    def get_operation_definition_information(self, employee_id: int,
                                             operation_definition_id: int):
        """ Retrieve information about an operation.
        The operation is meant to be imputable.

        FIXME That is a problem : if the operation is not imputable, one
        should still be able to report an "end of task" (bu not "start task")
        """

        opdef = dao.operation_definition_dao.find_by_id_frozen(
            operation_definition_id, commit=False, resilient=True)

        if not opdef:
            raise ServerException(ServerErrors.operation_definition_unknown,
                                  operation_definition_id)

        next_action_kind = dao.operation_definition_dao.find_next_action_for_employee_operation_definition(
            employee_id, operation_definition_id, at_time=datetime.now())
        session().commit()
        return opdef, next_action_kind
示例#11
0
    def get_person_data(self, employee_id: int, start_date: date):
        """ Get a lot of information about a person :
        * person data (totally independent of the start_date)
        * presence hours per day (on a period of 4 days, sorted from the oldest
          to th emost recent)

        The data are given on a specific date. The data are collected
        over a period of 3 days before the given start date.

        WARNING : To make sure the presence information is correct,
        a presence TAR may have to be recorded before calling this.
        """

        # FIXME I think about adding the activity hours instead of the presence hours

        if not start_date:
            raise ServerException(ServerErrors.invalid_parameter, 'start_date')

        mainlog.debug("get_person_data {}".format(employee_id))
        # 120 calls
        # query+json 6.70s => 0.055s per call

        # start_date = date.today() + timedelta(-360)

        end_date = start_date
        start_date = end_date - timedelta(days=3)

        from koi.junkyard.services import services

        try:
            chrono_start()
            person = dao.employee_dao.find_by_id_frozen2(employee_id)
            # person = services.employees.find_by_id(employee_id)

            d = DictAsObj(person._asdict())
            d.password = None  # Don't give the password away !

            chrono_click("clock_service : get_person_data - 1")

            activity_hours = dao.employee_dao.find_activity(
                employee_id, start_date, end_date)
            presence_hours = dao.employee_dao.find_person_presence_for_period(
                employee_id, start_date, end_date)
            # activity_hours = services.employees.find_activity(employee_id, start_date, end_date)
            # presence_hours = services.employees.find_person_presence_for_period(employee_id, start_date, end_date)

            chrono_click("clock_service : get_person_data - 2")
            mainlog.debug("get_person_data Done")

            d.activity_hours = activity_hours
            d.presence_hours = presence_hours

            return d

        except OperationalError as e:
            mainlog.debug("Raising Server exception")
            raise ServerException(ServerErrors.db_error, str(e))

        except Exception as e:
            mainlog.debug("Raising Server exception-2")
            mainlog.exception(e)
            raise ServerException(ServerErrors.unknown_employee_id,
                                  employee_id)
示例#12
0
    def _load_operation_and_task_data(self, operation_id, machine_id):
        """ Load an operation and all its associated task_data
        The task data may not be there.
        """

        mainlog.debug("_load_operation_and_task_data")

        # We outer join on the tasks to majke sure to read the operation
        # even if there's no task.

        q = session().query(Operation.operation_id,
                            Order.accounting_label.label("order_accounting_label"),
                            OrderPart.label.label("order_part_label"),
                            OrderPart.description.label('order_part_description'),
                            Customer.fullname.label('customer_name'),
                            OperationDefinition.operation_definition_id,
                            OperationDefinition.short_id.label("operation_definition_short_id"),
                            Operation.description.label("operation_description"),
                            Operation.position.label("operation_position"),
                            and_(OperationDefinition.imputable == True,
                                 OperationDefinition.on_operation == True,
                                 Order.state == OrderStatusType.order_ready_for_production).label("imputable"),
                            TaskOnOperation.task_id,
                            TaskOnOperation.active.label("task_active")).\
            join(ProductionFile).\
            join(OrderPart).join(Order).\
            join(OperationDefinition, OperationDefinition.operation_definition_id == Operation.operation_definition_id).\
            join(Customer, Order.customer_id == Customer.customer_id).\
            outerjoin(TaskOnOperation,
                      and_(
                          TaskOnOperation.operation_id == Operation.operation_id,
                          TaskOnOperation.machine_id == machine_id)).\
            options(lazyload('*')).\
            filter( Operation.operation_id == operation_id) # None is for the outer join; "or" works, in [None, machine] doesn not.

        row = q.all()

        # We do a bit of result analysis to improve error reporting

        if len(row) > 1:
            raise Exception("_load_operation_and_task_data : Too many results")

        elif not row:

            c = session().query(Operation.operation_id,
                                OperationDefinition.imputable,
                                OperationDefinition.short_id.label("operation_definition_short_id"),
                                OperationDefinition.on_operation,
                                Order.accounting_label.label("order_accounting_label"),
                                OrderPart.label.label("order_part_label"),
                                OrderPart.state.label("order_part_state")).\
                join(ProductionFile).\
                join(OrderPart).\
                join(Order).\
                join(OperationDefinition, OperationDefinition.operation_definition_id == Operation.operation_definition_id).\
                filter(Operation.operation_id == operation_id).first()

            if not c:
                raise ServerException(ServerErrors.operation_unknown,
                                      operation_id)
            elif not c.imputable:
                raise ServerException(
                    ServerErrors.operation_definition_not_imputable,
                    c.operation_definition_short_id)
            elif c.order_part_state != OrderStatusType.order_ready_for_production:
                raise ServerException(
                    ServerErrors.order_part_not_in_production_unknown,
                    "{}{}".format(c.order_accounting_label,
                                  c.order_part_label))

        return row[0]
示例#13
0
def print_order_report(dao, order_id, test_mode=False):
    global header_text,sub_header_text

    mainlog.debug('print_order_report order_id={}'.format(order_id))

    o = dao.order_dao.find_by_id(order_id)

    header_text = u"{} [{}]".format(o.customer.fullname, o.customer_order_name)
    sub_header_text = u"Mode op\u00E9ratoire"

    big_order_nr = ParagraphStyle(name = "subtitle", fontName = 'Helvetica-Bold', fontSize=24, leading=26)

    topstyle = ParagraphStyle(name = "zou", fontName = 'Helvetica', fontSize=16)

    p = platypus.Paragraph(u"<b>Client {}, commande #{}</b>".format(o.customer.customer_id,o.accounting_label),topstyle)
    spacer = platypus.Spacer(1,50)

    centered = ParagraphStyle(name = "zou", fontName = 'Helvetica-bold', alignment=TA_CENTER, fontSize=14) #, borderWidth=1, borderColor=colors.black)
    s = ParagraphStyle(name = "zou", fontName = 'Helvetica', fontSize=14, leading=16) #, borderWidth=1, borderColor=colors.black)
    page_number_style = ParagraphStyle(name = "page_number_style", fontName = 'Helvetica', alignment=TA_RIGHT, fontSize=12, leading=12) #, borderWidth=1, borderColor=colors.black)
    opNumberStyle = ParagraphStyle(name = "zou", fontName = 'Helvetica-bold', alignment=TA_CENTER, fontSize=28,leading=28) #, borderWidth=1, borderColor=colors.black)
    complete_document = []

    global satisfied
    satisfied = False
    sections.clear()
    headings_frame = HeadingsFrame(*basic_frame_dimensions)
    # complete_document.append(DocAssign("i",0))

    for part in o.parts:

        # Build up a table with accompanying style

        # data_ops = [ ['Poste',None,u'Op\u00E9ration',None] ]

        # We build up a data model and the appropriate styling information

        titles_row = []

        if part.production_file and len(part.production_file[0].operations) > 0:

            data_ops = [[Paragraph(part.human_identifier,big_order_nr),
                         Paragraph(escape_html(part.description),subtitle_style)],
                        [SubSectionNumber(part.human_identifier, page_number_style),
                         Paragraph(_("Quantity : {} - Deadline: {}").format(part.qty, date_to_dmy(part.deadline)),subtitle_style)]]

            ts = platypus.TableStyle()
            ts.add('GRID',(0,0),(-1,-1),0.5,colors.black)
            ts.add('VALIGN', (0, 0), (-1, -1), 'TOP')
            ts.add('ALIGN', (0, 1), (-1, 1), 'RIGHT')


            start_mark = PageMarker()
            complete_document.append( start_mark)

            header_maker = HeaderMaker(data_ops, ts, col_widths=compute_strut([3.8*cm, None], A4[0]-1*cm))
            complete_document.append(HeaderSetter( header_maker))

            operation_ndx = 1
            for op in part.production_file[0].operations:
                complete_document.append(
                    KeepTogether( [
                        make_boxes(operation_ndx, op, test_mode),
                        platypus.Spacer(1,0.1*cm) ] ))

                operation_ndx += 1

            end_mark = PageMarker()
            complete_document.append( end_mark)
            sections[part.human_identifier] = (start_mark, end_mark)

            complete_document.append(HeaderSetter(None))
            complete_document.append(PageBreak())
            # complete_document.append(platypus.Spacer(1,30))

    session().close() # FIXME Dirty

    if len(complete_document) > 0:
        filename = make_pdf_filename("OrderAndParts_{}_".format(order_id))
        ladderDoc = basic_PDF(filename,body_frame=headings_frame)
        ladderDoc.subject = u"Mode op\u00E9ratoire"
        ladderDoc.title = u"Client {}".format(o.customer.customer_id)

        ladderDoc.multiBuild(complete_document,canvasmaker=NumberedCanvas)
        open_pdf(filename)
        return True
    else:
        raise ServerException( ServerErrors.printing_an_empty_report)