Esempio n. 1
0
def new_production_order():
    form = CreateProductionOrderForm()
    stage = {'crumbroot': '/production'}
    if form.validate_on_submit():
        try:
            sno = form.prod_order_sno.sno.data
            with get_session() as session:
                title = form.prod_order_title.data.strip()
                if not sno:
                    sno = get_serialno(series='PROD', efield=title,
                                       register=True, session=session)
                else:
                    # additional sno validation?
                    pass

                cards = {x['ident']: int(x['qty']) for x in form.modules.data if x['ident']}
                deltas = [{'orig-cardname': x['orig_cardname'],
                           'target-cardname': x['target_cardname'],
                           'sno': x['sno']}
                          for x in form.deltas.data if x['sno']]
                requested_by = get_username_from_full_name(full_name=form.user.data,
                                                           session=session)
                # Construct Production Order
                prod_order = order.ProductionOrder(sno=sno)
                prod_order.create(
                    title=form.prod_order_title.data.strip(),
                    desc=form.desc.data.strip(),
                    cards=cards,
                    deltas=deltas,
                    sourcing_order_snos=None,
                    root_order_snos=form.root_order_sno.data,
                    ordered_by=requested_by,
                )
                # Check for Authorization
                # Nothing right now.
                # Create Order

                # TODO detach at this point
                fe_workspace_path = os.path.join(TEMPDIR, 'frontend')
                if not os.path.exists(fe_workspace_path):
                    os.makedirs(fe_workspace_path)
                workspace_path = os.path.join(fe_workspace_path, get_tempname())
                os.makedirs(workspace_path)
                prod_order.process(outfolder=workspace_path,
                                   register=True, session=session)
                shutil.rmtree(workspace_path)
                # Redirect to Created Order
            return redirect(url_for('.production_orders', order_sno=str(sno)))
        except AuthChainNotValidError:
            stage['auth_not_valid'] = True

    stage_crumbs = {'breadcrumbs': [Crumb(name="Production", path=""),
                                    Crumb(name="Orders", path="order/"),
                                    Crumb(name="New", path="order/new")],
                    }
    stage.update(stage_crumbs)
    pagetitle = "Create New Production Order"
    return render_template('production_order_new.html', stage=stage, form=form,
                           pagetitle=pagetitle)
Esempio n. 2
0
def generate_docs(invoice,
                  target_folder=None,
                  serialno=None,
                  register=False,
                  efield=None):
    """
    Generates all the Customs related documentation given a CustomsInvoice
    (or subclass) instance.

    :param invoice: The invoice object with customs information
    :type invoice: :class:`tendril.sourcing.customs.CustomsInvoice`
    :param target_folder: The folder in which the generated files
                          should be written to. Auto sets to Instance scratch
                          folder if None
    :type target_folder: str
    :param serialno: The serial number of the Customs documentation set.
                     Autogenerates if None.
    :type serialno: str
    :param register: Whether or not to register in the docstore.
                     Default False.
    :type register: bool
    :param efield: Additional short note to identify the document in the
                   store. Autogenerates from invoice if None.
    :type efield: str
    :return: The serial number of the generated document set.

    .. rubric:: Included Document Sets

    * Sumbmittable Documents, generated by :func:`gen_submitdocs`
    * Verification Documents, generated by :func:`gen_verificationdocs`

    """
    if efield is None:
        efield = ' '.join([invoice.vendor_name, str(invoice.inv_no)])
    if serialno is None:
        if os.path.exists(os.path.join(invoice.source_folder, 'wsno')):
            with open(os.path.join(invoice.source_folder, 'wsno'), 'r') as f:
                serialno = f.readline()
        else:
            serialno = serialnos.get_serialno(series='PINV',
                                              efield=efield,
                                              register=register)
    if target_folder is None:
        target_folder = invoice.source_folder
    files = gen_submitdocs(invoice, target_folder, serialno=serialno)
    files.extend(
        gen_verificationdocs(invoice, target_folder, serialno=serialno))
    files.extend(invoice.source_files)
    if register is True:
        for document in files:
            docstore.register_document(serialno=serialno,
                                       docpath=document[0],
                                       doctype=document[1],
                                       efield=efield,
                                       series='PINV')
    return serialno
Esempio n. 3
0
def generate_docs(invoice, target_folder=None,
                  serialno=None, register=False, efield=None):
    """
    Generates all the Customs related documentation given a CustomsInvoice
    (or subclass) instance.

    :param invoice: The invoice object with customs information
    :type invoice: :class:`tendril.sourcing.customs.CustomsInvoice`
    :param target_folder: The folder in which the generated files
                          should be written to. Auto sets to Instance scratch
                          folder if None
    :type target_folder: str
    :param serialno: The serial number of the Customs documentation set.
                     Autogenerates if None.
    :type serialno: str
    :param register: Whether or not to register in the docstore.
                     Default False.
    :type register: bool
    :param efield: Additional short note to identify the document in the
                   store. Autogenerates from invoice if None.
    :type efield: str
    :return: The serial number of the generated document set.

    .. rubric:: Included Document Sets

    * Sumbmittable Documents, generated by :func:`gen_submitdocs`
    * Verification Documents, generated by :func:`gen_verificationdocs`

    """
    if efield is None:
        efield = ' '.join([invoice.vendor_name, str(invoice.inv_no)])
    if serialno is None:
        if os.path.exists(os.path.join(invoice.source_folder, 'wsno')):
            with open(os.path.join(invoice.source_folder, 'wsno'), 'r') as f:
                serialno = f.readline()
        else:
            serialno = serialnos.get_serialno(series='PINV',
                                              efield=efield,
                                              register=register)
    if target_folder is None:
        target_folder = invoice.source_folder
    files = gen_submitdocs(invoice, target_folder, serialno=serialno)
    files.extend(
        gen_verificationdocs(invoice, target_folder, serialno=serialno)
    )
    files.extend(
        invoice.source_files
    )
    if register is True:
        for document in files:
            docstore.register_document(serialno=serialno, docpath=document[0],
                                       doctype=document[1],
                                       efield=efield, series='PINV')
    return serialno
Esempio n. 4
0
def render_po(stage, templateid, outpath):
    """
    Generates a purchase order using the template indicated by ``templateid``.

    :param stage: The dictionary to be sent along to the jinja2 template.
    :type stage: dict
    :param templateid: The id of the template to use.
    :type templateid: str
    :param outpath: The path to which the output should be written,
                    including ``.pdf``.
    :type outpath: str
    :return: The ``outpath``.

    .. rubric:: Template Used

    This function uses a template specified by ``templateid``, specifically,
    using the template named ``po_[templateid]_template.tex``.

    .. rubric:: Stage Keys Provided

    The contents of the ``stage`` provided to the jinja2 template are specific
    to each template, and it is the responsibility of the caller to make sure
    that it contains all the keys that the template expects. The parts of the
    stage defined by this function, common to all templates, are :

    .. list-table::

        * - ``no``
          - The serial number of the purchase order, either from the ``stage``
            parameter or created.
        * - ``point``
          - The name of the contact person, defined by
            :data:`tendril.config.legacy.COMPANY_PO_POINT`.
        * - ``date``
          - The purchase order date, either from the ``stage`` parameter or
            today's date.
        * - ``lcofile``
          - The latex lcofile to use, defined by
            :data:`tendril.config.legacy.COMPANY_PO_LCO_PATH`

    """
    template = 'po_' + templateid + '_template.tex'
    stage['lcofile'] = COMPANY_PO_LCO_PATH
    if 'point' not in stage.keys():
        stage['point'] = COMPANY_PO_POINT
    if 'no' not in stage.keys():
        stage['no'] = serialnos.get_serialno(series='PO', efield=templateid)
    if 'date' not in stage.keys():
        stage['date'] = str(datetime.date.today())
    return render.render_pdf(stage, template, outpath)
Esempio n. 5
0
def render_po(stage, templateid, outpath):
    """
    Generates a purchase order using the template indicated by ``templateid``.

    :param stage: The dictionary to be sent along to the jinja2 template.
    :type stage: dict
    :param templateid: The id of the template to use.
    :type templateid: str
    :param outpath: The path to which the output should be written,
                    including ``.pdf``.
    :type outpath: str
    :return: The ``outpath``.

    .. rubric:: Template Used

    This function uses a template specified by ``templateid``, specifically,
    using the template named ``po_[templateid]_template.tex``.

    .. rubric:: Stage Keys Provided

    The contents of the ``stage`` provided to the jinja2 template are specific
    to each template, and it is the responsibility of the caller to make sure
    that it contains all the keys that the template expects. The parts of the
    stage defined by this function, common to all templates, are :

    .. list-table::

        * - ``no``
          - The serial number of the purchase order, either from the ``stage``
            parameter or created.
        * - ``point``
          - The name of the contact person, defined by
            :data:`tendril.utils.config.COMPANY_PO_POINT`.
        * - ``date``
          - The purchase order date, either from the ``stage`` parameter or
            today's date.
        * - ``lcofile``
          - The latex lcofile to use, defined by
            :data:`tendril.utils.config.COMPANY_PO_LCO_PATH`

    """
    template = 'po_' + templateid + '_template.tex'
    stage['lcofile'] = COMPANY_PO_LCO_PATH
    if 'point' not in stage.keys():
        stage['point'] = COMPANY_PO_POINT
    if 'no' not in stage.keys():
        stage['no'] = serialnos.get_serialno(series='PO', efield=templateid)
    if 'date' not in stage.keys():
        stage['date'] = str(datetime.date.today())
    return render.render_pdf(stage, template, outpath)
Esempio n. 6
0
    def _process(self, outfolder=None, manifestsfolder=None,
                 label_manager=None, register=False, force=False,
                 pb_class=None, stacked_pb=False, leaf_pb=True,
                 session=None):
        self._force = force

        if pb_class is None:
            pb_class = TendrilProgressBar

        if stacked_pb is True:
            pb = pb_class(max=8)
        else:
            pb = DummyProgressBar(max=8)

        pb.next(note="Constructing Resources for Production Order Generation")

        if outfolder is None:
            if self._order_yaml_path is not None:
                outfolder = os.path.split(self._order_yaml_path)[0]
            else:
                raise AttributeError('Output folder needs to be defined')

        if manifestsfolder is None:
            manifestsfolder = os.path.join(outfolder, 'manifests')
            if not os.path.exists(manifestsfolder):
                os.makedirs(manifestsfolder)

        if self._sno is None:
            self._sno = serialnos.get_serialno(
                    series='PROD', efield=self._title,
                    register=register, session=session
            )

        # Create Snomap
        if self._snomap_path is not None:
            with open(self._snomap_path, 'r') as f:
                self._snomap = SerialNumberMap(yaml.load(f), self._sno)
        else:
            self._snomap = SerialNumberMap({}, self._sno)

        self._snomap.set_session(session=session)
        if register is True:
            self._snomap.enable_creation()

        indent_sno = self._snomap.get_sno('indentsno')
        if register is True:
            serialnos.link_serialno(child=indent_sno, parent=self.serialno,
                                    verbose=False, session=session)

        # Create cards and deltas and so forth
        pb.next(note="Constructing Production Order Actions")
        actions = self.card_actions + self.delta_actions

        pb.next(note="Executing Production Order Actions")
        for action in actions:
            if register is False:
                action.scaffold = True
            action.set_session(session=session)
            action.commit(
                outfolder=manifestsfolder, indent_sno=indent_sno,
                prod_ord_sno=self._sno, register=register, session=session,
                pb_class=pb_class, stacked_pb=stacked_pb, leaf_pb=leaf_pb,
            )

        self._snomap.disable_creation()

        pb.next(note="Constructing Composite Output BOM")
        cobom = CompositeOutputBom(self.bomlist)

        pb.next(note="Creating Indent(s)")
        self._process_indents(
            indent_sno=indent_sno, cobom=cobom, outfolder=outfolder,
            register=register, force=force, session=session
        )

        pb.next(note="Generating Production Order Document")
        # Make production order doc
        self._last_generated_at = arrow.utcnow().isoformat()
        if self._first_generated_at is None:
            self._first_generated_at = arrow.utcnow().isoformat()
        self._dump_order_yaml(outfolder=outfolder, register=register,
                              session=session)
        self._generate_doc(outfolder=outfolder, register=register,
                           session=session)

        pb.next(note="Generating Labels")
        self.make_labels(label_manager=label_manager, pb_class=pb_class,
                         stacked_pb=stacked_pb, leaf_pb=leaf_pb)

        pb.next(note="Finalizing Production Order")
        for action in actions:
            action.scaffold = False
            action.unset_session()
        self._snomap.dump_to_file(outfolder)
        self._snomap.unset_session()

        if register is True:
            docstore.register_document(
                    serialno=self.serialno,
                    docpath=os.path.join(outfolder, 'snomap.yaml'),
                    doctype='SNO MAP', efield=self.title,
                    verbose=False, session=session
            )
        pb.finish()
        self._defined = True
Esempio n. 7
0
def new_indent(indent_sno=None):
    form = CreateIndentForm(parent_indent_sno=indent_sno)
    stage = {'crumbroot': '/inventory'}
    if form.validate_on_submit():
        try:
            with get_session() as session:
                sno = form.indent_sno.sno.data
                if not sno:
                    if indent_sno is not None:
                        sno = form.get_supplementary_sno_default()
                        register_serialno(sno=sno,
                                          efield="WEB FRONTEND INDENT",
                                          session=session)
                    else:
                        sno = get_serialno(series='IDT',
                                           efield='WEB FRONTEND INDENT',
                                           register=True,
                                           session=session)
                else:
                    # additional sno validation?
                    pass
                nindent = InventoryIndent(sno=sno, session=session)
                # Construct COBOM
                obom = create_obom_from_listing(form.components.data,
                                                'MANUAL (WEB)')
                cobom = CompositeOutputBom([obom],
                                           name='MANUAL (WEB) {0}'.format(sno))

                requested_by = get_username_from_full_name(
                    full_name=form.user.data, session=session)

                icparams = {
                    'cobom': cobom,
                    'title': form.indent_title.data,
                    'desc': form.indent_desc.data,
                    'requested_by': requested_by,
                    'rdate': form.rdate.data or arrow.utcnow(),
                    'indent_type': form.indent_type.data,
                }
                nindent.create(**icparams)

                root_order_sno = form.root_order_sno.data
                prod_order_sno = form.prod_order_sno.data
                try:
                    nindent.define_auth_chain(prod_order_sno=prod_order_sno,
                                              root_order_sno=root_order_sno,
                                              session=session)
                except AuthChainNotValidError:
                    raise
                nindent.register_auth_chain(session=session)

                fe_workspace_path = os.path.join(TEMPDIR, 'frontend')
                if not os.path.exists(fe_workspace_path):
                    os.makedirs(fe_workspace_path)
                workspace_path = os.path.join(fe_workspace_path,
                                              get_tempname())
                os.makedirs(workspace_path)

                nindent.process(outfolder=workspace_path,
                                register=True,
                                session=session)

                shutil.rmtree(workspace_path)
            return redirect(url_for('.indent', indent_sno=str(sno)))
        except AuthChainNotValidError:
            stage['auth_not_valid'] = True

    if indent_sno is None:
        stage_crumbs = {
            'breadcrumbs': [
                Crumb(name="Inventory", path=""),
                Crumb(name="Indent", path="indent/"),
                Crumb(name="New", path="indent/new")
            ],
        }
        pagetitle = "Create New Indent"
    else:
        stage_crumbs = {
            'breadcrumbs': [
                Crumb(name="Inventory", path=""),
                Crumb(name="Indent", path="indent/"),
                Crumb(name=indent_sno, path="indent/" + indent_sno),
                Crumb(name="New",
                      path='/'.join(["indent", indent_sno, "/new"])),
            ]
        }
        pagetitle = "New Supplementary Indent for " + indent_sno
    stage.update(stage_crumbs)
    return render_template('indent_new.html',
                           stage=stage,
                           form=form,
                           pagetitle=pagetitle)
Esempio n. 8
0
def new_production_order():
    form = CreateProductionOrderForm()
    stage = {'crumbroot': '/production'}
    if form.validate_on_submit():
        try:
            sno = form.prod_order_sno.sno.data
            with get_session() as session:
                title = form.prod_order_title.data.strip()
                if not sno:
                    sno = get_serialno(series='PROD',
                                       efield=title,
                                       register=True,
                                       session=session)
                else:
                    # additional sno validation?
                    pass

                cards = {
                    x['ident']: int(x['qty'])
                    for x in form.modules.data if x['ident']
                }
                deltas = [{
                    'orig-cardname': x['orig_cardname'],
                    'target-cardname': x['target_cardname'],
                    'sno': x['sno']
                } for x in form.deltas.data if x['sno']]
                requested_by = get_username_from_full_name(
                    full_name=form.user.data, session=session)
                # Construct Production Order
                prod_order = order.ProductionOrder(sno=sno)
                prod_order.create(
                    title=form.prod_order_title.data.strip(),
                    desc=form.desc.data.strip(),
                    cards=cards,
                    deltas=deltas,
                    sourcing_order_snos=None,
                    root_order_snos=form.root_order_sno.data,
                    ordered_by=requested_by,
                )
                # Check for Authorization
                # Nothing right now.
                # Create Order

                # TODO detach at this point
                fe_workspace_path = os.path.join(TEMPDIR, 'frontend')
                if not os.path.exists(fe_workspace_path):
                    os.makedirs(fe_workspace_path)
                workspace_path = os.path.join(fe_workspace_path,
                                              get_tempname())
                os.makedirs(workspace_path)
                prod_order.process(outfolder=workspace_path,
                                   register=True,
                                   session=session)
                shutil.rmtree(workspace_path)
                # Redirect to Created Order
            return redirect(url_for('.production_orders', order_sno=str(sno)))
        except AuthChainNotValidError:
            stage['auth_not_valid'] = True

    stage_crumbs = {
        'breadcrumbs': [
            Crumb(name="Production", path=""),
            Crumb(name="Orders", path="order/"),
            Crumb(name="New", path="order/new")
        ],
    }
    stage.update(stage_crumbs)
    pagetitle = "Create New Production Order"
    return render_template('production_order_new.html',
                           stage=stage,
                           form=form,
                           pagetitle=pagetitle)
Esempio n. 9
0
    def _process(self, outfolder=None, manifestsfolder=None,
                 label_manager=None, register=False, force=False,
                 pb_class=None, stacked_pb=False, leaf_pb=True,
                 session=None):
        self._force = force

        if pb_class is None:
            pb_class = TendrilProgressBar

        if stacked_pb is True:
            pb = pb_class(max=8)
        else:
            pb = DummyProgressBar(max=8)

        pb.next(note="Constructing Resources for Production Order Generation")

        if outfolder is None:
            if self._order_yaml_path is not None:
                outfolder = os.path.split(self._order_yaml_path)[0]
            else:
                raise AttributeError('Output folder needs to be defined')

        if manifestsfolder is None:
            manifestsfolder = os.path.join(outfolder, 'manifests')
            if not os.path.exists(manifestsfolder):
                os.makedirs(manifestsfolder)

        if self._sno is None:
            self._sno = serialnos.get_serialno(
                    series='PROD', efield=self._title,
                    register=register, session=session
            )

        # Create Snomap
        if self._snomap_path is not None:
            with open(self._snomap_path, 'r') as f:
                self._snomap = SerialNumberMap(yaml.load(f), self._sno)
        else:
            self._snomap = SerialNumberMap({}, self._sno)

        self._snomap.set_session(session=session)
        if register is True:
            self._snomap.enable_creation()

        indent_sno = self._snomap.get_sno('indentsno')
        if register is True:
            serialnos.link_serialno(child=indent_sno, parent=self.serialno,
                                    verbose=False, session=session)

        # Create cards and deltas and so forth
        pb.next(note="Constructing Production Order Actions")
        actions = self.card_actions + self.delta_actions

        pb.next(note="Executing Production Order Actions")
        for action in actions:
            if register is False:
                action.scaffold = True
            action.set_session(session=session)
            action.commit(
                outfolder=manifestsfolder, indent_sno=indent_sno,
                prod_ord_sno=self._sno, register=register, session=session,
                pb_class=pb_class, stacked_pb=stacked_pb, leaf_pb=leaf_pb,
            )

        self._snomap.disable_creation()

        pb.next(note="Constructing Composite Output BOM")
        cobom = CompositeOutputBom(self.bomlist)

        # Assume Indent is non-empty.
        # Create indent
        pb.next(note="Creating Indent")
        indent = InventoryIndent(indent_sno, verbose=False, session=session)
        indent.create(cobom, title="FOR {0}".format(self.serialno),
                      desc=None, indent_type='production',
                      requested_by=self._ordered_by, force=force)
        indent.define_auth_chain(prod_order_sno=self.serialno,
                                 session=session, prod_order_scaffold=True)
        indent.process(outfolder=outfolder, register=register,
                       verbose=False, session=session)
        self._indents.append(indent)

        pb.next(note="Generating Production Order Document")
        # Make production order doc
        self._last_generated_at = arrow.utcnow().isoformat()
        if self._first_generated_at is None:
            self._first_generated_at = arrow.utcnow().isoformat()
        self._dump_order_yaml(outfolder=outfolder, register=register,
                              session=session)
        self._generate_doc(outfolder=outfolder, register=register,
                           session=session)

        pb.next(note="Generating Labels")
        self.make_labels(label_manager=label_manager, pb_class=pb_class,
                         stacked_pb=stacked_pb, leaf_pb=leaf_pb)

        pb.next(note="Finalizing Production Order")
        for action in actions:
            action.scaffold = False
            action.unset_session()
        self._snomap.dump_to_file(outfolder)
        self._snomap.unset_session()

        if register is True:
            docstore.register_document(
                    serialno=self.serialno,
                    docpath=os.path.join(outfolder, 'snomap.yaml'),
                    doctype='SNO MAP', efield=self.title,
                    verbose=False, session=session
            )
        pb.finish()
        self._defined = True
Esempio n. 10
0
def new_indent(indent_sno=None):
    form = CreateIndentForm(parent_indent_sno=indent_sno)
    stage = {'crumbroot': '/inventory'}
    if form.validate_on_submit():
        try:
            with get_session() as session:
                sno = form.indent_sno.sno.data
                if not sno:
                    if indent_sno is not None:
                        sno = form.get_supplementary_sno_default()
                        register_serialno(sno=sno, efield="WEB FRONTEND INDENT",
                                          session=session)
                    else:
                        sno = get_serialno(series='IDT',
                                           efield='WEB FRONTEND INDENT',
                                           register=True, session=session)
                else:
                    # additional sno validation?
                    pass
                nindent = InventoryIndent(sno=sno, session=session)
                # Construct COBOM
                obom = create_obom_from_listing(form.components.data,
                                                'MANUAL (WEB)')
                cobom = CompositeOutputBom([obom],
                                           name='MANUAL (WEB) {0}'.format(sno))

                requested_by = get_username_from_full_name(full_name=form.user.data,
                                                           session=session)

                icparams = {
                    'cobom': cobom,
                    'title': form.indent_title.data,
                    'desc': form.indent_desc.data,
                    'requested_by': requested_by,
                    'rdate': form.rdate.data or arrow.utcnow(),
                    'indent_type': form.indent_type.data,
                }
                nindent.create(**icparams)

                root_order_sno = form.root_order_sno.data
                prod_order_sno = form.prod_order_sno.data
                try:
                    nindent.define_auth_chain(prod_order_sno=prod_order_sno,
                                              root_order_sno=root_order_sno,
                                              session=session)
                except AuthChainNotValidError:
                    raise
                nindent.register_auth_chain(session=session)

                fe_workspace_path = os.path.join(TEMPDIR, 'frontend')
                if not os.path.exists(fe_workspace_path):
                    os.makedirs(fe_workspace_path)
                workspace_path = os.path.join(fe_workspace_path, get_tempname())
                os.makedirs(workspace_path)

                nindent.process(outfolder=workspace_path,
                                register=True, session=session)

                shutil.rmtree(workspace_path)
            return redirect(url_for('.indent', indent_sno=str(sno)))
        except AuthChainNotValidError:
            stage['auth_not_valid'] = True

    if indent_sno is None:
        stage_crumbs = {'breadcrumbs': [Crumb(name="Inventory", path=""),
                                        Crumb(name="Indent", path="indent/"),
                                        Crumb(name="New", path="indent/new")],
                        }
        pagetitle = "Create New Indent"
    else:
        stage_crumbs = {'breadcrumbs': [Crumb(name="Inventory", path=""),
                                        Crumb(name="Indent", path="indent/"),
                                        Crumb(name=indent_sno,
                                              path="indent/" + indent_sno),
                                        Crumb(name="New",
                                              path='/'.join(["indent",
                                                             indent_sno,
                                                             "/new"])),
                                        ]
                        }
        pagetitle = "New Supplementary Indent for " + indent_sno
    stage.update(stage_crumbs)
    return render_template('indent_new.html', stage=stage, form=form,
                           pagetitle=pagetitle)