Пример #1
0
    def validate(self, user=None):
        if user:
            self.created_by = user
        super(InventoryMovement, self).validate()
        # make sure all children has batch number if our doc_type is NOT IN GR
        if not self.is_good_received() or self.cancel is not None:
            if any(i.batch is None for i in self.items):
                raise ValidationError(_("ERROR_BATCH_IS_REQUIRED"))

        if self.is_good_issued():
            if any(i.quantity > 0 for i in self.items) and self.cancel is None:
                raise ValidationError(
                    _("ERROR_GOOD_ISSUE_QUANTITY_MUST_BE_NEGATIVE"))
            if any(i.quantity < 0
                   for i in self.items) and self.cancel is not None:
                raise ValidationError(
                    _("ERROR_CANCELLED_GOOD_ISSUE_QUANTITY_MUST_BE_POSITIVE"))

        if self.is_transfer():
            if len(self.items) % 2 != 0:
                raise ValidationError(
                    _("ERROR_TRANSFER_MUST_HAVE_EVEN_NUMBER_OF_ITEMS"))

        # Validate based on Good Received, Good Issued, SA, etc. logic
        InventoryContent.apply(self, True)
Пример #2
0
    def confirm(self, user, confirmation, **kwargs):
        """

        :param IntraUser user:
        :param AuxiliaryTaskConfirmation confirmation:
        :param dict kwargs: materials
        :return:
        """
        if self.status >= self.STATUS_CONFIRMED:
            raise ValidationError(
                _("ERROR_TASK_STATUS_CANT_CONFIRM: %(status)s") %
                {'status': self.status})

        if not confirmation:
            raise ValidationError(_("ERROR_CONFIRMATION_IS_REQUIRED"))

        if not isinstance(confirmation, AuxiliaryTaskConfirmation):
            raise ValidationError(
                _("ERROR_CONFIRMATION_MUST_BE_AUX_TASK_CONFIRMATION"))

        if not confirmation.materials:
            raise ValidationError(_("ERROR_MATERIAL_IS_REQUIRED"))

        if not self.confirmations:
            self.actual_start = confirmation.actual_start

        self.actual_duration += confirmation.actual_duration

        # if confirmation is marked completed, set status to confirmed
        if confirmation.completed:
            self.actual_end = confirmation.actual_end
            self.status = self.STATUS_CONFIRMED

        super(AuxiliaryTask, self).confirm(user, confirmation, **kwargs)
Пример #3
0
    def create(cls, requester, authenticated_by, authentication_challenge,
               target_permissions):
        """

        :param IntraUser requester:
        :param IntraUser authenticated_by:
        :param basestring authentication_challenge:
        :param basestring|list target_permissions:
        :raise ValidationError:
        :return Authentication:
        """
        # sanitize input
        if isinstance(target_permissions, basestring):
            target_permissions = [target_permissions]

        # Validate if target user has enough permission allow such task to happen?
        if any(not authenticated_by.can(p) for p in target_permissions):
            raise ValidationError(
                _("ERR_AUTHENTICATE_USER_DOES_NOT_HAVE_TARGET_PERMISSION: %(target_permissions)s"
                  ) % {'target_permissions': ",".join(target_permissions)})

        # Validate password challenge
        if not authenticated_by.check_password(authentication_challenge):
            raise ValidationError(_("ERR_AUTHENTICATION_FAILED"))

        # Validated, success create the token
        o = cls()
        o.target_permissions = target_permissions
        o.requester = requester
        o.authorizer = authenticated_by
        o.created = NOW()
        o.save()
        return o
Пример #4
0
    def validate(self):
        # FIXME: Check UOM
        for index, item in enumerate(self.items):
            material = MaterialMaster.factory(item.material)
            revisions = material.revisions()
            if revisions:
                revision_list = [rev.rev_id for rev in revisions]
                if item.revision not in revision_list:
                    raise ValidationError(
                        _("ERROR_REVISION_DOES_NOT_EXIST: %(material)s in item %(itemnumber)s only has revision %(revisionlist)s"
                          ) % {
                              'material': item.material.code,
                              'itemnumber': index + 1,
                              'revisionlist': revision_list
                          })

                schematic = filter(lambda r: item.revision is r.rev_id,
                                   revisions)[0]
                if item.size and item.size not in schematic.conf_size:
                    raise ValidationError(
                        _("ERROR_SIZE_DOES_NOT_EXIST: %(material)s revision %(materialrevision)s in item %(itemnumber)s only has size %(sizelist)s"
                          ) % {
                              'material': item.material.code,
                              'materialrevision': schematic.rev_id,
                              'itemnumber': index + 1,
                              'sizelist': schematic.conf_size
                          })
Пример #5
0
    def translate(input, output='label', allow_incomplete=False):

        if output not in ['label', 'object', 'extract']:
            raise BadParameterError("output format '%s' is invalid" % output)

        # assume default type = 'stock'
        (type, code) = input.split('-', 1) if '-' in input else ('stock',
                                                                 input)

        c = typed_code_factory(type, code)

        if c is None:
            raise ValidationError("Unable to parse '%s'" % code)

        if not allow_incomplete and output not in ['extract'
                                                   ] and len(c.leftover) > 0:
            raise ValidationError(
                "Unable to parse partial of code near '%s' of %s" %
                (c.leftover, str(c)))

        if 'label' == output:
            return c.tail().label

        if 'extract' == output:
            return c.trail

        return c
Пример #6
0
 def normalize(self, for_size_index):
     o = self.__class__()
     # simple stuff
     o.id = self.id
     o.process = self.process
     o.source = self.source[:]
     o.is_configurable = False
     o.labor_cost = self.labor_cost
     o.markup = self.markup
     o.remark = self.remark
     # nested stuff
     o.materials = map(lambda a: a.normalized(for_size_index),
                       self.materials)
     # size sensitive stuff
     if not self.is_configurable:
         o.duration = self.duration[:]
         o.staging_duration = self.staging_duration[:]
     else:
         if not (0 <= for_size_index < len(self.duration)):
             raise ValidationError(
                 _("ERR_NORMALIZE_SCHEMATIC_ENTRY_FAILED_DURATION_SIZE_INDEX_OUT_OF_RANGE"
                   ))
         if not (0 <= for_size_index < len(self.staging_duration)):
             raise ValidationError(
                 _("ERR_NORMALIZE_SCHEMATIC_ENTRY_FAILED_STAGING_DURATION_SIZE_INDEX_OUT_OF_RANGE"
                   ))
         o.duration = [self.duration[for_size_index]]
         o.staging_duration = [self.staging_duration[for_size_index]]
     return o
Пример #7
0
    def validate_pair(design_uid, code):
        """
        Validate design_uid + code

        - Validate design_uid is not obligated to something else but "code"
        - then Validate "code" is not yet taken

        :param design_uid:
        :param code:
        :return: true, is already paired, false if not yet paired, throw if error
        """
        try:
            o = DesignUID(design_uid)
            if o.code is None:
                # design_uid is NEW
                # your design_uid is not yet bind, meaning your status is not Approved yet.
                pass

            # design_uid already exists, validate if value is correct
            if o.code != code:
                raise ValidationError("%s: check_code=%s, uid_based_code=%s" % (_("ERROR_DESIGN_UID_MISMATCHED"), code, o.code))
            return True
        except ValueError:
            # design_uid not exist, let's check if code is already taken or not?
            if DesignUID.lookup(code) is not None:
                raise ValidationError("%s: %s" % (_("ERROR_DESIGN_UID_ALREADY_IN_USED"), code))
            return False
Пример #8
0
    def append(self, code_, label_, **kwargs):
        if not len(code_) == self.length:
            raise ValidationError('Supplied code "%s" must have size of %d' %
                                  (code_, self.length))
        # check if code_ already exists
        queried = models.LOV.objects.filter(self._get_filter() & Q(code=code_))
        if queried.count() > 0:
            raise ValidationError('Code "%s" already exists.' % code_)

        models.LOV(group=self.groupValue(), code=code_, label=label_).save()
        return True
Пример #9
0
    def cancel(self, user, **kwargs):
        if self.status == self.STATUS_CLOSED:
            raise ValidationError(_("ERROR_CANNOT_CANCEL_CLOSED_PR"))

        if self.status == self.STATUS_CANCELLED:
            raise ValidationError(_("ERROR_PR_ALREADY_CANCELLED"))

        self.status = self.STATUS_CANCELLED
        self.cancelled = doc.Event.create(doc.Event.CANCELLED,
                                          user,
                                          against=self)
        self.touched(user, **kwargs)
Пример #10
0
    def set_delivered(self, user):
        if self.status < self.STATUS_CONFIRMED:
            raise ValidationError(
                _("ERROR_STORE_TASK_MUST_BE_CONFIRMED: %(status)s") %
                {'status': self.status})

        if self.status >= self.STATUS_DELIVERED:
            raise ValidationError(
                _("ERROR_TASK_STATUS_CANT_DELIVERED: %(status)s") %
                {'status': self.status})

        self.status = self.STATUS_DELIVERED
        self.touched(user)
Пример #11
0
    def append(self, code_, title_, **kwargs):
        if not len(code_) == self.length:
            raise ValidationError('Supplied code "%s" must have size of %d' %
                                  (code_, self.length))

        # check if code_ already exists
        queried = Company.objects.filter(code=code_)
        if queried.count() > 0:
            raise ValidationError('Code "%s" already exists.' % code_)

        comp = Company(code=code_, title=title_)
        if 'author' in kwargs:
            comp.author = kwargs['author']
        comp.save()

        return True
Пример #12
0
    def factory(cls, type, items, ref_doc=None):
        """
        Create InventoryMovement

        :param type:
        :param items: array of tuple or list of (material_code, quantity)
        :param ref_doc:
        :return:
        """
        # Sanitize 'items' based on 'type'
        if type in [cls.GI_CC, cls.GI_PD, cls.GI_SC, cls.GI_SO]:
            # Convert incoming tuple to InventoryMovementEntry
            pass
        elif type in [cls.GR_PD, cls.GR_PR, cls.GR_BP, cls.GR_LT]:
            # Convert incoming tuple to InventoryMovementEntry
            pass
        elif type in [cls.ST_LL, cls.ST_LP, cls.ST_PL, cls.ST_MM, cls.ST_LT]:
            # Let it go ~~
            pass
        else:
            raise ValidationError(
                'Factory method cannot handle document type of %s.' % type)
        o = cls()
        o.type = type
        o.items = items
        o.ref_doc = ref_doc
        return o
Пример #13
0
    def revert(self, user):
        """
        Revert StoreAuxTask while cancelling all the existing Confirmations.

        :param IntraUser user:
        :return:
        """
        if self.status == self.STATUS_CONFIRMED:
            # Cancel all existing confirmations
            for conf in filter(lambda c: not c.is_cancelled(),
                               self.confirmations):
                conf.cancel(cancelled_by=user)

            # Revert the values to original state.
            self.actual_duration = 0
            self.actual_start = None
            self.actual_end = None
            self.status = self.STATUS_OPEN

            # Save it.
            self.touched(user)
            signals.task_reverted.send(self.__class__,
                                       instance=self,
                                       reverted_cotnent=[])
            return True

        raise ValidationError(
            _("ERR_CANNOT_REVERT_DELIVERED_TASK: %(task_doc_no)s") %
            {'task_doc_no': self.doc_no})
Пример #14
0
 def __init__(self, group_, length_, parent_=None):
     super(HierarchyLovComponent, self).__init__(group_, length_)
     if parent_ is not None and not isinstance(parent_, models.LOV):
         raise ValidationError(
             'Parent provided must be models.LOV class, received %s instead'
             % type(parent_))
     self.parent = parent_
Пример #15
0
    def cancel(self, user, **kwargs):
        if self.cancelled:
            raise ValidationError(_("ERROR_TASK_IS_ALREADY_CANCELLED"))

        self.cancelled = doc.Event.create(doc.Event.CANCELLED,
                                          user,
                                          against=self)

        self.touched(user, **kwargs)
Пример #16
0
    def assert_assignee(self, assignee):
        """
        Validate if assignee as IntraUser is applicable for the task.

        :param assignee:
        :return:
        """
        if isinstance(assignee, IntraUser):
            if not assignee.can("write", self.task.code):
                raise ValidationError(
                    _("ERR_INVALID_ASSIGNEE: %(user)s %(task_code)s") % {
                        'user': self.assignee,
                        'task_code': self.task.code
                    })
        elif isinstance(assignee, TaskGroup):
            if self.task.default_assignee() is not self.assignee:
                raise ValidationError(
                    _("ERR_INVALID_ASSIGNEE: %(group)s %(task_code)s") % {
                        'task_code': self.task.code,
                        'group': self.assignee
                    })
Пример #17
0
    def query_content(cls,
                      material=None,
                      location=None,
                      batch=None,
                      ref_doc=None,
                      **kwargs):
        """
        A thin wrapper to make a inventory content query easier

        :param material:
        :param location:
        :param batch:
        :param ref_doc:
        :param kwargs:
        :return:
        """
        cond = {
            'material': material,
            'location': location,
            'batch': batch,
            'ref_doc': ref_doc
        }
        # sanitize
        # (1) remove all none attributes
        del_keys = []
        for k in cond:
            if cond[k] is None:
                del_keys.append(k)
        for k in del_keys:
            del cond[k]

        # (2) String attributes
        for k in ['material', 'location', 'batch']:
            if k in cond:
                cond[k] = str(cond[k])
        # (3) take care of ref_doc field
        if 'ref_doc' in cond:
            if isinstance(cond['ref_doc'], doc.Doc):
                cond['ref_doc.0'] = cond['ref_doc'].object_id
                cond['ref_doc.1'] = cond['ref_doc'].manager.collection_name
                del cond['ref_doc']
            elif isinstance(cond['ref_doc'], ObjectId):
                cond['ref_doc.0'] = cond['ref_doc']
                del cond['ref_doc']
            else:
                raise ValidationError(
                    _("ERR_QUERY_CONTENT_CANNOT_INTERPRET_PARAMETER: %(parameter)s %(type)s"
                      ) % {
                          'parameter': 'ref_doc',
                          'type': type(cond['ref_doc'])
                      })
        # query
        return cls.manager.find(cond=cond)
Пример #18
0
            def normalize(size_index, size_code):
                # update code
                # sanity check
                if not isinstance(master_model_code, codes.StockCode):
                    raise ValidationError(_("ERR_CANNOT_NORMALIZE_MASTER_MODEL_CODE_SHOULD_BE_STOCK_CODE"))

                # update code
                new_code_str = master_model_code.code + size_code
                new_code = codes.StockCode(new_code_str)

                # map normalize process
                return new_code, map(lambda p: p.normalize(size_index), processes)
Пример #19
0
    def add(self, quantity, value, weight):
        new_quantity = self.quantity + quantity
        new_value = self.value + value
        if new_quantity < 0:
            raise ValidationError(
                _("ERROR_INSUFFICIENT_QUANTITY: %(content_signature)s %(content_quantity)s + %(additional_quantity)s < 0"
                  ) % {
                      'content_quantity': self.quantity,
                      'additional_quantity': quantity,
                      'content_signature': str(self)
                  })

        new_weight = None
        if weight is not None or self.weight is not None:
            new_weight = (self.weight or 0) + (weight or 0)
            if new_weight < 0:
                raise ValidationError(
                    "%s: %s + %s < 0" %
                    (_("ERROR_UNBALANCE_WEIGHT"), self.weight, weight))

        self.quantity = new_quantity
        self.value = new_value
        self.weight = new_weight
Пример #20
0
    def compare(pattern_, code_):
        if isinstance(pattern_, TypedCode):
            pattern_ = str(pattern_)
        elif isinstance(pattern_, basestring):
            pattern_ = pattern_
        else:
            raise ValidationError('Unable to handle %s' % type(pattern_))

        p = re.compile(
            '^' +
            re.sub(r'#+', lambda x:
                   ('[#0-9a-z]{' + str(len(x.group(0))) + '}'), pattern_),
            re.IGNORECASE)
        return p.match(
            str(code_.code) if isinstance(code_, TypedCode) else code_
        ) is not None
Пример #21
0
 def normalized(self, for_size_index):
     o = self.__class__()
     # easy stuff
     o.code = self.code
     o.is_configurable = False
     o.counter = self.counter
     o.cost = self.cost
     # size sensitive stuff
     if not self.is_configurable:
         o.quantity = self.quantity[:]
     else:
         if len(self.quantity) <= for_size_index or for_size_index < 0:
             raise ValidationError(
                 _("ERR_NORMALIZE_SCHEMATIC_ENTRY_FAILED_MATERIAL_QUANTITY_SIZE_INDEX_OUT_OF_RANGE"
                   ))
         o.quantity = [self.quantity[for_size_index]]
     return o
Пример #22
0
    def touched(self, user, **kwargs):
        """

        :param IntraUser user:
        :param kwargs:
        :return:
        """
        # Check permission
        if not kwargs.pop("automated", False):
            self.assert_permission(user, self.PERM_W, self.type)

        # initialisation of conditional default value
        if self.doc_no is not None or not self.is_new():
            raise ValidationError(_("MATERIAL_MOVEMENT_IS_NOT_EDITABLE"))
        super(InventoryMovement, self).touched(user, **kwargs)

        # Post the changes to InventoryContent
        InventoryContent.apply(self)
Пример #23
0
    def lookup(cls, design_code_with_revision, single=False):
        """

        :param design_code_with_revision:
        :param single: return only one result or None
        :return: Array of Design object matched design_code
        """
        if design_code_with_revision is None:
            raise BadParameterError("Required non-None design code string")
        # validate input first
        matches = re.compile(r'^([A-Z0-9-]+)(r(\d+))?').match(design_code_with_revision)
        if not matches:
            raise BadParameterError("Invalid design code %s" % design_code_with_revision)

        groups = matches.groups()

        design_uid = groups[0]
        design_rev = groups[2]

        design_uid = DesignUID.lookup(design_uid)

        if design_uid is None:
            raise ValidationError("Design UID %s not found." % design_uid)

        cond = {
            'rev_unique_id': design_uid.object_id
        }

        if design_rev is not None:
            cond['rev_id'] = int(design_rev)

        r = cls.manager.find(cond=cond)
        if single:
            return r[len(r)-1] if len(r) > 0 else None
        else:
            return r
Пример #24
0
def room_dashboard(request, room_code, doc_no, action):
    try:
        room = Room.factory(room_code)
    except KeyError:
        raise BadParameterError(_("ERR_UNABLE_TO_IDENTIFY_ROOM"))

    if request.method == 'POST':
        if action is None:
            raise BadParameterError.required('action')

        if action == 'deliverable':
            """
            POST Method, action="deliverable"

            Probe Job Tags for delivery candidates

            If condition met: all(previous_op.status == DELIVERED) and ClerkAuxTask.is_confirmed() then adjust operation
            status to READY.

            :returns [{}] deliverable
            """
            if doc_no is None or len(doc_no) == 0:
                raise BadParameterError.required('production_order_doc_no')

            production_order = ProductionOrder.of('doc_no', doc_no)

            # User requested to update these task as "Ready"
            if production_order is None:
                raise BadParameterError(
                    _("ERR_UNKNOWN_PRODUCTION_ORDER: %(doc_no)s") %
                    {'doc_no': doc_no})
            ready_operations = production_order.pending_tasks(
                lambda operation: operation.task in room.tasks)

            # Only previous operation of ready_operations where by ...
            #   => prev_op.status == STATUS_CONFIRMED
            def traverse():
                for ready_op in ready_operations:
                    for prev_op in ready_op.previous_op():
                        if prev_op.status == ProductionOrderOperation.STATUS_CONFIRMED:
                            yield prev_op

            return map(
                lambda a: {
                    'doc_no': a.doc_no,
                    'object_id': str(a.object_id),
                    'task': a.task.code
                }, traverse())
        elif action == "delivered":
            """
            POST Method, action="delivered"

            Assign Delivered status to provided doc_no, and set next_op to ready if possible...

            :raises BadParameter if doc_no is not ``TaskDocNo``
            :returns Boolean
            """
            if doc_no is None or len(doc_no) == 0:
                raise BadParameterError.required('task_doc_no')

            production_order_operation = ProductionOrderOperation.of(
                'doc_no', doc_no)

            if production_order_operation is None:
                raise BadParameterError(
                    _("ERR_UNKNOWN_PRODUCTION_ORDER_OPERATION_DOC_NO: %(doc_no)s"
                      ) % {'doc_no': doc_no})

            # Check if we can set this doc status to ready or not?
            if production_order_operation.status != ProductionOrderOperation.STATUS_CONFIRMED:
                raise ValidationError(
                    _("ERR_UNABLE_TO_UPDATE_UNCONFIRMED_OPERATION_TO_DELIVERED: %(doc_no)s"
                      ) % {'doc_no': doc_no})

            # Update the status
            production_order_operation.status = ProductionOrderOperation.STATUS_DELIVERED
            production_order_operation.touched(request.user)

            production_order_operation.ready_next_operation_if_possible(
                author=request.user, context_room=room)
            return True

        raise BadParameterError(
            _("ERR_UNSUPPORTED_ACTION: %(action)s") % {'action': action})

    if request.method == 'GET':
        # Query all parent task within the room
        results = ProductionOrderOperation.manager.find(
            cond={
                'planned_start': {
                    '$lt': datetime.today().replace(
                        hour=23, minute=59, second=59)
                },
                '$and': [{
                    'status': {
                        '$gte': ProductionOrderOperation.STATUS_RELEASED
                    }
                }, {
                    'status': {
                        '$lt': ProductionOrderOperation.STATUS_CONFIRMED
                    }
                }],
                'task': {
                    '$in': room.tasks
                }
            })
        ref_docs = list(set(o.ref_doc[0] for o in results))

        orders = ProductionOrder.manager.project({'_id': {
            '$in': ref_docs
        }},
                                                 project=['_id', 'doc_no'])
        # query clerk's auxiliary task status
        aux_tasks = ClerkAuxTask.manager.aggregate([{
            "$group": {
                "_id": "$parent_task",
                "status": {
                    "$min": "$status"
                }
            }
        }])
        aux_tasks = dict((a['_id'], a['status']) for a in aux_tasks['result'])

        def process_task_output(a):
            r = a.serialized()
            # patch with previous_op statues
            previous_ops = []
            for prev_op in a.previous_op():
                previous_ops.append({
                    'object_id': str(prev_op.object_id),
                    'task': prev_op.task.code,
                    'doc_no': prev_op.doc_no,
                    'status': prev_op.status
                })
            r['previous_ops'] = previous_ops
            # patch with aux_task status
            key = a.object_id
            r['clerk_confirmed'] = aux_tasks[key] if key in aux_tasks else 0
            return r

        return {
            'orders':
            dict(map(lambda a: (str(a['_id']), a['doc_no']), orders)),
            'tasks':
            map(process_task_output, results),
            'activities':
            map(lambda a: a.as_json(), UserActiveTask.probe_all(results))
        }
Пример #25
0
    def extract_master_models(self, verbose=False):
        """
        Extract all task stoppers and its first make that matched: stock-###021 (mold)

        :return: list of tuple(StockCode, uom, [SchematicEntry])
        """
        output = []
        if len(self.master_modeling) <= 0:
            return output

        if verbose:
            print("Extraction Begun")
            for p in self.master_modeling:
                print "\t I: ", p

        indices = dict((p.id, p) for p in self.master_modeling)
        last_process = self.master_modeling[-1]

        ValidationError.raise_if(not is_task_stopper(last_process), _("ERROR_TASK_STOPPER_MUST_BE_LAST_PROCESS"))
        for final_process in reversed(filter(is_task_stopper, self.master_modeling)):
            if verbose:
                print("\t=> For %s" % final_process)
            # populate it
            buffer = [final_process]
            processes = []
            # populate until buffer depleted
            while len(buffer) > 0:
                p = buffer.pop()
                processes.append(copy.deepcopy(p))
                for proc_id in p.source:
                    buffer.append(indices[proc_id])

            # Clean up result
            # 1. Identify the final material_code (make of sprue)
            # 2. Place the schematic with correct placement of process.
            _pttrn = _TASK_STOPPER_PAIRS[str(final_process.process)]

            def is_target_make(m):
                return codes.TypedCode.compare(_pttrn, m.code) and m.quantity[0] < 0

            # List all makes
            makes = dict(map(lambda m: (m.code, m), filter(is_target_make, processes[0].materials)))
            if verbose:
                print "\t=> output!", makes
            if len(makes) > 1:
                # if we have more than 1 make, then get only the one without pair
                borrows = dict(map(lambda m: (m.code, m), filter(lambda m: m.code in makes and m.quantity[0] > 0, processes[0].materials)))
                diff_key = set(makes) - set(borrows)
                map(makes.__delitem__, diff_key)        # Delete all borrows items from make list

            # Sanity check
            ValidationError.raise_if(len(makes) != 1, _("ERROR_UNABLE_TO_IDENTIFY_MASTER_MODEL"))

            # material to create from the final process
            material_to_create = makes.popitem()[1]

            # Remove the material from the process
            del processes[0].materials[processes[0].materials.index(material_to_create)]

            # Make sure the order of process is correct
            processes.reverse()

            # TODO: Normalize existing ID/Source binding

            # Append to output array
            output.append((material_to_create.code, material_to_create.counter, processes))

        if verbose:
            print("Done")
        return output
Пример #26
0
    def transfer_pair_factory(cls,
                              material,
                              quantity,
                              from_location,
                              to_location,
                              from_ref_doc=None,
                              to_ref_doc=None):
        """

        :param material:
        :param quantity:
        :param from_location:
        :param to_location:
        :param from_ref_doc:
        :param to_ref_doc:
        :return: cursor of InventoryMovementEntry
        """
        # Query inventory content, FIFO
        batch_candidate = InventoryContent.manager.project(
            cond={
                'material': str(material),
                'location': from_location,
                'quantity': {
                    '$gt': 0
                }
            },
            project=['_id', 'batch', 'quantity', 'value', 'weight'],
            sort=[("batch", 1)])

        leftover = quantity
        usage_tuples = []  # batch, quantity, value, weight
        for a in batch_candidate:
            batch_quantity = float(a['quantity'])
            used = min(batch_quantity, leftover)
            consumption_ratio = used / batch_quantity
            delta_value = float(a['value']) * consumption_ratio
            delta_weight = float(a['weight']) * consumption_ratio
            leftover -= used
            usage_tuples.append((a['batch'], used, delta_value, delta_weight))
            if leftover <= 0:
                break
        if leftover > 0:
            raise ValidationError(
                _('ERR_FAILED_TO_ALLOCATE_MATERIAL_TRANSFER_PAIR: %(material)s %(from_location)s %(to_location)s'
                  ) % {
                      'material': material,
                      'from_location': from_location,
                      'to_location': to_location
                  })

        def create():
            for p in usage_tuples:
                o = cls()
                o.material = material
                o.quantity = -p[1]
                o.batch = p[0]
                o.value = -p[2]
                o.weight = -p[3]
                o.ref_doc = from_ref_doc
                o.location = from_location
                yield o
                i = cls()
                i.material = material
                i.quantity = p[1]
                i.batch = p[0]
                i.value = p[2]
                i.weight = p[3]
                i.ref_doc = to_ref_doc
                i.location = to_location
                yield i

        return create()
Пример #27
0
 def validate(self):
     for item in self.items:
         if not item.open_quantity:
             item.open_quantity = item.quantity
         elif item.open_quantity > item.quantity:
             raise ValidationError(_("ERROR_OPEN_QTY_MORE_THAN_QTY"))
Пример #28
0
def typed_code_factory(type, code):
    if type in TYPED_CODES:
        return TYPED_CODES[type](code)
    raise ValidationError('Unknown type_code type: "%s"' % type)
Пример #29
0
    def validate(self):
        if not self.task:
            raise ValidationError(_("ERROR_TASK_IS_REQUIRED"))

        if self.assignee is None:
            self.assignee = self.task.default_assignee()
Пример #30
0
 def check(code_):
     if '-' not in code_:
         raise ValidationError('%s is invalid' % code_)