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)
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
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
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)
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)
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
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)
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)
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
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)