def create_design(): """Create new design. This method is always called via AJAX.""" form = CreateDesignForm(request.form) validated, design_numbers = form.validate_on_submit() if validated: designs = [] for design_number in design_numbers: variables = { 'design_number': design_number, 'name': form.name.data, 'project': form.project.data, 'revision': form.revision.data, 'owner': form.owner.data } # TODO: Create both design and part in one transaction, so if Part create fails, design create fails # Create the design design = Design.create(**variables) # Create part -1 (dash one) on design item variables = { 'design': design, 'owner': design.owner, 'part_identifier': 1 } Part.create(**variables) designs.append(design.as_dict() ) # For modal if user creates more than one Design jsonData = {'designs': designs} return jsonify(jsonData), 200, {'ContentType': 'application/json'} else: response = make_response( render_template('design/create_design_modal.html', form=form), 500) return response
def create_proc(): """Create new Procedure.""" form = CreateProcedureForm(request.form) validated = form.validate_on_submit() if validated: kwargs = { 'name': form.name.data, 'owner': form.owner.data, 'project': form.project.data } procedure = Procedure.create(**kwargs) part_ids = [] if request.form['parts'] == '' else request.form[ 'parts'].split(',') vendor_part_ids = [] if request.form[ 'vendor_parts'] == '' else request.form['vendor_parts'].split(',') for part_id in part_ids: part = Part.get_by_id(part_id) procedure.parts.append(part) for vendor_part_id in vendor_part_ids: part = VendorPart.get_by_id(vendor_part_id) procedure.vendor_parts.append(part) procedure.save() jsonData = {'success': True, 'url': procedure.get_url()} return jsonify(jsonData), 200, {'ContentType': 'application/json'} else: part_ids = [] if request.form['parts'] == '' else request.form[ 'parts'].split(',') vendor_part_ids = [] if request.form[ 'vendor_parts'] == '' else request.form['vendor_parts'].split(',') parts = [] vendor_parts = [] for part_id in part_ids: part = Part.get_by_id(part_id) parts.append(part) for vendor_part_id in vendor_part_ids: part = VendorPart.get_by_id(vendor_part_id) vendor_parts.append(part) variables = { 'vendor_parts': vendor_parts, 'parts': parts, 'current_part_ids': request.form['parts'], 'current_vendor_part_ids': request.form['vendor_parts'], 'form': form } return make_response( render_template('procedure/create_procedure.html', **variables), 500)
def add_extra_product_component(): form = AddExtraProductComponentForm(request.form) validated = form.validate_on_submit() if validated: quantity = form.quantity.data part_group = form.part_group.data part_id = form.part_id.data product_id = form.product_id.data product = Product.get_by_id(product_id) ordering = len(product.extra_components) + 1 if part_group == 'Part': # part_group from typeahead group, not class name part = Part.get_by_id(part_id) for i in range(quantity): epc = ExtraProductComponent.create(parent=product, part=part, ordering=ordering) elif part_group == 'Vendor Part': # part_group from typeahead group, not class name vendor_part = VendorPart.get_by_id(part_id) for i in range(quantity): epc = ExtraProductComponent.create(parent=product, vendor_part=vendor_part, ordering=ordering) components_array = arrange_product_components(product) extra_components_array = arrange_extra_product_components(product) variables = { 'success': True, 'product': product, 'components_array': components_array, 'extra_components_array': extra_components_array } new_value = '{0} - Quantity: {1}'.format(epc.get_part().get_descriptive_url(), quantity) product.add_change_log_entry(action='Add', field='Extra Component', new_value=new_value) return render_template('product/as-built/component_list.html', **variables) else: product_id = form.product_id.data product = Product.get_by_id(product_id) part = None if form.part_id.data: part_group = form.part_group.data part_id = form.part_id.data if part_group == 'Part': # part_group from typeahead, not class name part = Part.get_by_id(part_id) elif part_group == 'Vendor Part': # part_group from typeahead, not class name part = VendorPart.get_by_id(part_id) variables = { 'form': form, 'product': product, 'part': part } response = make_response(render_template('product/add_product_component_modal.html', **variables), 500) return response
def update_part_revision(procedure_id, part_id): # TODO: Change this away from hardcoded URL, but using ajax select field now which just calls this as api_url proc = Procedure.get_by_id(procedure_id) procedure = Procedure.get_by_id(procedure_id) new_part_id = request.form['value'] part = Part.get_by_id(part_id) new_part = Part.get_by_id(new_part_id) # Remove association to part from old revision procedure.parts.remove(part) # Add new association to part from new revision procedure.parts.append(new_part) procedure.save() return render_template('procedure/procedure_part.html', part=new_part, proc=proc)
def remove_part(): procedure_id = request.form.get('procedure_id') part_type = request.form.get('part_type') part_id = request.form.get('part_id') proc = Procedure.get_by_id(procedure_id) part = None if part_type == "designs": part = Part.get_by_id(part_id) proc.parts.remove(part) elif part_type == "vendor_parts": part = VendorPart.get_by_id(part_id) proc.vendor_parts.remove(part) proc.add_change_log_entry(action='Remove', field='Part', original_value=part.get_descriptive_url()) proc.save() jsonData = {'success': True, 'partId': part_id} return jsonify(jsonData), 200, {'ContentType': 'application/json'}
def get_record_by_id_and_class(record_id, record_class): # TODO: Try to find a better way that doesn't involve so much dynamic loading record = None record_class = record_class.lower() # Just in case if record_class == 'anomaly': from pid.anomaly.models import Anomaly record = Anomaly.get_by_id(record_id) elif record_class == 'asrun': from pid.asrun.models import AsRun record = AsRun.get_by_id(record_id) elif record_class == 'build': from pid.product.models import Build record = Build.get_by_id(record_id) elif record_class == 'design': from pid.design.models import Design record = Design.get_by_id(record_id) elif record_class == 'eco': from pid.eco.models import ECO record = ECO.get_by_id(record_id) elif record_class == 'part': from pid.part.models import Part record = Part.get_by_id(record_id) elif record_class == 'procedure': from pid.procedure.models import Procedure record = Procedure.get_by_id(record_id) elif record_class == 'product': from pid.product.models import Product record = Product.get_by_id(record_id) elif record_class == 'specification': from pid.specification.models import Specification record = Specification.get_by_id(record_id) elif record_class == 'task': from pid.task.models import Task record = Task.get_by_id(record_id) elif record_class == 'vendorbuild': from pid.vendorproduct.models import VendorBuild record = VendorBuild.get_by_id(record_id) elif record_class == 'vendorpart': from pid.vendorpart.models import VendorPart record = VendorPart.get_by_id(record_id) elif record_class == 'vendorproduct': from pid.vendorproduct.models import VendorProduct record = VendorProduct.get_by_id(record_id) return record
def add_part(): procedure_id = request.form.get('procedure_id') record_id = request.form.get('record_id') record_class = request.form.get('record_class') proc = Procedure.get_by_id(procedure_id) part = None if record_class == "part": part = Part.get_by_id(record_id) proc.parts.append(part) elif record_class == "vendorpart": part = VendorPart.get_by_id(record_id) proc.vendor_parts.append(part) proc.add_change_log_entry(action='Add', field='Part', new_value=part.get_descriptive_url()) proc.save() return render_template('procedure/procedure_part.html', part=part, proc=proc)
def get_procedure_modal(): form = CreateProcedureForm(request.form) vendor_parts = [] parts = [] table = request.form.get('table', None) part_id = request.form.get('part_id', None) if table: if table == 'vendor_parts': vendor_parts.append(VendorPart.get_by_id(part_id)) elif table == 'designs': parts.append(Part.get_by_id(part_id)) variables = { 'vendor_parts': vendor_parts, 'parts': parts, 'current_part_ids': ','.join([str(x.id) for x in parts]), 'current_vendor_part_ids': ','.join([str(x.id) for x in vendor_parts]), 'form': form } return render_template('procedure/create_procedure.html', **variables)
def revise_design(): form = ReviseDesignForm(request.form) validated = form.validate_on_submit() if not validated: design_id = form.design_id.data design = Design.get_by_id(design_id) variables = {'design': design, 'form': form} return make_response( render_template('design/revise_design_modal.html', **variables), 500) old_design_id = form.design_id.data new_revision = form.revision.data reason = form.revision_reason.data new_owner = form.owner.data include_parts = request.form['include_parts'] old_design = Design.get_by_id(old_design_id) # Get the old bits while we can parts = old_design.parts links = old_design.links documents = old_design.documents images = old_design.images references_to = old_design.references_to # TODO: Duplicate anomalies, ecos, specifications, produres, family, changelog, revisionlog replace_values = { 'revision': new_revision, 'owner': new_owner, 'created_by': current_user, 'state': old_design.workflow.initial_state, 'export_control': old_design. export_control, # Because make_transient uses default values 'self_approved': Design.self_approved.default.arg } design = old_design.clone( replace_values ) # After this point, old_design is the same as design, a cloned instance # Clone all parts if include_parts == 'all': for old_part in parts: # TODO: Parent? Changelog? components = old_part.components replace_values = {'design': design} part = old_part.clone(replace_values) for old_component in components: replace_values = { 'parent': part, 'part': old_component.part, 'vendor_part': old_component.vendor_part, 'quantity': old_component. quantity # Because make_transient uses default values } old_component.clone(replace_values) # Clone selected parts else: include_selected_parts = request.form.getlist('include_selected_parts') for part_id in include_selected_parts: # TODO: Parent? Changelog? old_part = Part.get_by_id(part_id) components = old_part.components replace_values = {'design': design} part = old_part.clone(replace_values) for old_component in components: replace_values = { 'parent': part, 'part': old_component.part, 'vendor_part': old_component.vendor_part, 'quantity': old_component. quantity # Because make_transient uses default values } old_component.clone(replace_values) # Clone links for old_link in links: link = old_link.clone() design.links.append(link) # Clone documents for old_document in documents: document = old_document.clone_document(design) design.documents.append(document) # Clone images for old_image in images: image = old_image.clone_image(design) design.images.append(image) # Clone what this references for reference in references_to: Reference.create(by_id=design.id, by_class=design.get_class_name(), to_id=reference.to_id, to_class=reference.to_class) # Create new change log and new workflow log design.change_log = ChangeLog.create() design.workflow_log = WorkflowLog.create() # Add supervisor approval if user is a padawan if current_user.padawan: approver = Approver.create(approver_id=current_user.supervisor_id, capacity='Supervisor') design.approvers.append(approver) design.save() # Update any references in part components from old revision to new revision PartComponent.update_part_component_references(design) # Update revision log design.revision_log.add_entry(design.revision, reason, current_user) jsonData = {'success': True, 'url': design.get_url()} return jsonify(jsonData), 200, {'ContentType': 'application/json'}
def validate(self): """Validate the form.""" initial_validation = super(CreateBuildForm, self).validate() errors = False data = {} if not initial_validation: errors = True part = Part.get_by_id(self.part_id.data) existing_serial_numbers = Product.get_serial_numbers_for_design_number_and_part_identifier( part.design.design_number, part.part_identifier) if self.product_type.data == 's/n': # TODO: Try to move some of this to an external function, very messy now return_serial_numbers = [] # TODO: Improve these replaces serial_numbers = self.serial_numbers.data.strip().replace( ' , ', ',').replace(', ', ',').replace(' ,', ',').replace( ' ', ',') # In case user uses space instead of comma if len(serial_numbers) == 0: self.serial_numbers.errors.append('No S/N(s) entered') errors = True else: # First check for comma separated serial_numbers if ',' in serial_numbers: serial_numbers_array = serial_numbers.split(',') # In these, check for ranges and validate and append for sn in serial_numbers_array: if '-' in sn: serial_numbers_range_low = sn.split('-')[0] serial_numbers_range_high = sn.split('-')[1] validated_low = self.validate_serial_number( serial_numbers_range_low) validated_high = self.validate_serial_number( serial_numbers_range_high) if validated_low and validated_high: for i in range(int(validated_low), int(validated_high) + 1): validated_sn = self.validate_serial_number( i) if validated_sn in existing_serial_numbers: self.serial_numbers.errors.append( 'S/N {0} already exists'.format( validated_sn)) errors = True else: return_serial_numbers.append( validated_sn) else: self.serial_numbers.errors.append( 'Invalid S/N(s) entered') errors = True # If not range, append the validated values else: validated_sn = self.validate_serial_number(sn) if validated_sn: if validated_sn in existing_serial_numbers: self.serial_numbers.errors.append( 'S/N {0} already exists'.format( validated_sn)) errors = True else: return_serial_numbers.append(validated_sn) else: self.serial_numbers.errors.append( 'Invalid S/N(s) entered') errors = True # Only range present elif '-' in serial_numbers: serial_numbers_range_low = serial_numbers.split('-')[0] serial_numbers_range_high = serial_numbers.split('-')[1] validated_low = self.validate_serial_number( serial_numbers_range_low) validated_high = self.validate_serial_number( serial_numbers_range_high) if validated_low and validated_high: for i in range(int(validated_low), int(validated_high) + 1): validated_sn = self.validate_serial_number(i) if validated_sn in existing_serial_numbers: self.serial_numbers.errors.append( 'S/N {0} already exists'.format( validated_sn)) errors = True else: return_serial_numbers.append(validated_sn) else: self.serial_numbers.errors.append( 'Invalid S/N(s) entered') errors = True pass # Only one S/N present most likely, just append it after validating else: validated_sn = self.validate_serial_number(serial_numbers) if validated_sn: if validated_sn in existing_serial_numbers: self.serial_numbers.errors.append( 'S/N {0} already exists'.format(validated_sn)) errors = True else: return_serial_numbers.append(validated_sn) else: self.serial_numbers.errors.append( 'Invalid S/N(s) entered') errors = True data['serial_numbers'] = return_serial_numbers elif self.product_type.data == 'lot': return_lot_record = None lot_record = self.lot_record.data.strip() if len(lot_record) == 0: self.lot_record.errors.append('No LOT record entered') errors = True else: if lot_record[0] != 'L': # No biggie, just need to append L to beginning of number validated_lot_record = self.validate_serial_number( lot_record) if validated_lot_record: return_lot_record = 'L{0}'.format(validated_lot_record) else: self.lot_record.errors.append( 'Invalid LOT record entered') errors = True else: # Remove 'L' from beginning before validating, then add again. validated_lot_record = self.validate_serial_number( lot_record[1:]) if validated_lot_record: return_lot_record = 'L{0}'.format(validated_lot_record) else: self.lot_record.errors.append( 'Invalid LOT record entered') errors = True if lot_record in existing_serial_numbers: self.lot_record.errors.append( 'LOT record {0} already exists'.format(lot_record)) errors = True else: data['lot_record'] = return_lot_record elif self.product_type.data == 'stock': # TODO: Check if STCK already exists if 'STCK' in existing_serial_numbers: self.product_type.errors.append('STCK already exists') errors = True else: data['is_stock'] = True if errors: return False, None return True, data
def create_build(): """Create new Build. Also creates one or more Products.""" form = CreateBuildForm(request.form) if request.method == 'GET': part = Part.get_by_id(request.args.get('part_id')) existing_build_id = request.args.get('existing_build_id') if existing_build_id: existing_build = Build.get_by_id(existing_build_id) build_identifier = existing_build.build_identifier else: build_identifier = Build.get_next_build_identifier_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier) lot_identifier = Product.get_next_lot_number_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier) existing_serial_numbers = ','.join(Product.get_serial_numbers_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier)) # Pre-populate with values from design form.project.data = part.design.project variables = { 'form': form, 'part': part, 'build_identifier': build_identifier, 'lot_identifier': lot_identifier, 'existing_serial_numbers': existing_serial_numbers, 'existing_build_id': existing_build_id } return render_template('product/create_build_modal.html', **variables) validated, data = form.validate_on_submit() if validated: part = Part.get_by_id(form.part_id.data) vendor = form.vendor.data owner = form.owner.data build_identifier = form.build_identifier.data # Create build if form.existing_build_id.data: build = Build.get_by_id(form.existing_build_id.data) else: build = Build.create(part=part, vendor=vendor, owner=owner, build_identifier=build_identifier) # For each s/n in s/n, create product revision = part.design.revision summary = part.design.summary hardware_type = form.hardware_type.data project = form.project.data # Create serial numbers serial_numbers = data.get('serial_numbers', []) for sn in serial_numbers: product = Product.create(serial_number=sn, part=part, build=build, revision=revision, summary=summary, hardware_type=hardware_type, project=project, owner=owner) # Create Product Components for part_component in part.components: for i in range(part_component.quantity): if part_component.part: ProductComponent.create(parent=product, part=part_component.part, ordering=part_component.ordering) elif part_component.vendor_part: ProductComponent.create(parent=product, vendor_part=part_component.vendor_part, ordering=part_component.ordering) # Or create LOT product lot_record = data.get('lot_record', None) if lot_record: product = Product.create(serial_number=lot_record, part=part, build=build, revision=revision, summary=summary, hardware_type=hardware_type, product_type='LOT', project=project, owner=owner) # Create Product Components for part_component in part.components: for i in range(part_component.quantity): if part_component.part: ProductComponent.create(parent=product, part=part_component.part, ordering=part_component.ordering) elif part_component.vendor_part: ProductComponent.create(parent=product, vendor_part=part_component.vendor_part, ordering=part_component.ordering) # Or create STOCK product is_stock = data.get('is_stock', False) if is_stock: product = Product.create(serial_number='STCK', part=part, build=build, revision=revision, summary=summary, hardware_type=hardware_type, product_type='STOCK', project=project, owner=owner) jsonData = { 'success': True, 'product_number': product.product_number.replace(' ', '-') # Slugify product_number } return jsonify(jsonData), 200, {'ContentType': 'application/json'} else: part = Part.get_by_id(request.form['part_id']) build_identifier = Build.get_next_build_identifier_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier) lot_identifier = Product.get_next_lot_number_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier) existing_serial_numbers = ','.join(Product.get_serial_numbers_for_design_number_and_part_identifier(part.design.design_number, part.part_identifier)) variables = { 'form': form, 'part': part, 'build_identifier': build_identifier, 'lot_identifier': lot_identifier, 'existing_serial_numbers': existing_serial_numbers } response = make_response(render_template('product/create_build_modal.html', **variables), 500) return response
def get_nlas_for_vendor_part(self): return Part.get_nlas_for_vendor_part(self)