from flask_wtf import FlaskForm from wtforms import ( StringField, SelectField, DateField, SubmitField ) from wtforms.validators import ( DataRequired, Length, ValidationError ) def validate_tooling_id_format(form, field): """Custom validator to ensure tooling_id is exactly 5 digits""" if not field.data.isdigit() or len(field.data) != 5: raise ValidationError('Tooling ID must be exactly 5 digits') class QuotationForm(FlaskForm): # Factory Information mold_shop_name = StringField('Mold Shop Name', validators=[DataRequired()]) mold_shop_country = SelectField('Mold Shop Country', validators=[DataRequired()], choices=[ ('', 'Select Country'), ('China', 'China'), ('Vietnam', 'Vietnam'), ('Indonesia', 'Indonesia') ]) t1_shoe_factory_name = StringField('T1 Shoe Factory Name', validators=[DataRequired()]) t1_shoe_factory_country = SelectField('T1 Shoe Factory Country', validators=[DataRequired()], choices=[ ('', 'Select Country'), ('China', 'China'), ('Vietnam', 'Vietnam'), ('Indonesia', 'Indonesia') ]) t2_component_factory_name = StringField('T2 Component Factory Name', validators=[DataRequired()]) t2_component_factory_country = SelectField('T2 Component Factory Country', validators=[DataRequired()], choices=[ ('', 'Select Country'), ('China', 'China'), ('Vietnam', 'Vietnam'), ('Indonesia', 'Indonesia') ]) # Mold Information model_name = StringField('Model Name', validators=[DataRequired()]) tooling_id = StringField('Tooling ID', validators=[DataRequired(), Length(min=5, max=5), validate_tooling_id_format], id='tooling_id') season = StringField('Season', validators=[DataRequired()]) # Define stage-type mapping STAGE_TYPE_MAPPING = { 'CR0': ['Sample'], 'CR1': ['Sample'], 'CR2': ['Sample'], 'SMS': ['A Set'], 'commercialization': ['A Set'], 'production': ['Additional'] } # Define the mapping of main types to sub-types MOLD_TYPE_MAPPING = { 'Rubber': ['Flat Outsole', 'Cupsole', 'Rubber Sole'], 'CMEVA': ['2 Plates Mold', '3 Plates Mold', '2 Plates with in-mold channel', 'Breathable + in-mold channel'], 'IMEVA': ['2 Plates Mold', '3 Plates Mold'], 'Sandal': ['Sandal with Upper Bandage', '2 Plate without Upper Bandage'], 'Co-shot mold': ['Co-shot mold', 'Foaming mold'], 'PU': ['2 Plates Mold', '3 Plates Mold'] } # Define the mapping of sub-types to their specific options MOLD_SPECIFIC_TYPE_OPTIONS = { 'Flat Outsole': ['Flat', 'Flat with Top/Heel Tip'], 'Cupsole': ['Top PL', 'Visible PL'], 'Rubber Sole': ['Top PL', 'Short PL (Heel/Forefoot)', 'Visible PL', 'Wave PL'] } mold_main_type = SelectField('Mold Main Type', validators=[DataRequired()], choices=[ ('', 'Select Main Type'), ('Rubber', 'Rubber'), ('CMEVA', 'CMEVA'), ('IMEVA', 'IMEVA'), ('Sandal', 'Sandal'), ('Co-shot mold', 'Co-shot mold'), ('PU', 'PU') ], id='mold_main_type') mold_sub_type = SelectField('Mold Sub Type', validators=[DataRequired()], choices=[ ('', 'Select Sub Type') ], id='mold_sub_type') mold_specific_type = SelectField('Mold Specific Type', validators=[], choices=[ ('', 'Select Specific Type') ], id='mold_specific_type', coerce=str, default='') stage = SelectField('Stage', validators=[DataRequired()], choices=[ ('', 'Select Stage'), ('CR0', 'CR0'), ('CR1', 'CR1'), ('CR2', 'CR2'), ('SMS', 'SMS'), ('commercialization', 'Commercialization'), ('production', 'Production') ], id='stage') type = SelectField('Type', validators=[DataRequired()], choices=[ ('', 'Select Type'), ('Sample', 'Sample'), ('A Set', 'A Set'), ('Additional', 'Additional') ], id='type') # Dates and Approvals issue_date = DateField('Issue Date', validators=[DataRequired()]) approved_by_mold_shop = StringField('Approved by (Mold Shop Representative)', validators=[DataRequired()]) approved_by_t1_tooling = StringField('Approved by (T1 Tooling Representative)', validators=[DataRequired()]) approved_by_lo_tooling = StringField('Approved by (LO Tooling)', validators=[DataRequired()]) # Mold Cost sliders_count = SelectField('Number of Sliders', validators=[DataRequired()], choices=[ ('', 'Select Number of Sliders'), ('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4') ]) cavity_count = SelectField('Number of Cavities', validators=[DataRequired()], choices=[ ('', 'Select Number of Pairs'), ('0.5', '0.5 pair'), ('1', '1 pair'), ('1.5', '1.5 pair'), ('2', '2 pair'), ('2.5', '2.5 pair'), ('3', '3 pair') ]) digital_texture_type = SelectField('Digital Texture', validators=[DataRequired()], choices=[ ('', 'Select Texture Type'), ('adidas_digital', 'adidas digital texture'), ('customized texture', 'customized texture'), ('laser', 'laser texture') ]) complexity_high_sidewall = SelectField('High Sidewall >60mm', validators=[DataRequired()], choices=[('no', 'No'), ('yes', 'Yes')]) submit = SubmitField('Calculate') def __init__(self, *args, **kwargs): super(QuotationForm, self).__init__(*args, **kwargs) # Set initial choices for mold_sub_type based on default mold_main_type if self.mold_main_type.data in self.MOLD_TYPE_MAPPING: self.mold_sub_type.choices = [('', 'Select Sub Type')] + [(x, x) for x in self.MOLD_TYPE_MAPPING[self.mold_main_type.data]] def validate_mold_sub_type(self, field): main_type = self.mold_main_type.data print(f"Validating sub_type: {field.data} for main_type: {main_type}") if main_type and main_type in self.MOLD_TYPE_MAPPING: valid_sub_types = self.MOLD_TYPE_MAPPING[main_type] print(f"Valid sub_types for {main_type}: {valid_sub_types}") if field.data not in valid_sub_types and field.data != '': print(f"Invalid sub_type: {field.data}. Valid types: {valid_sub_types}") raise ValidationError('Invalid sub-type for selected main type') def validate_mold_specific_type(self, field): """Validate that the selected specific type is valid for the selected sub type.""" sub_type = self.mold_sub_type.data if not sub_type: field.data = '' return # Get valid specific types for the selected sub type valid_specific_types = self.MOLD_SPECIFIC_TYPE_OPTIONS.get(sub_type, []) # If there are no specific types for this sub-type, the field should be empty if not valid_specific_types: field.data = '' # Always clear the field if it shouldn't have a value return # If there are specific types, validate the selection if field.data is None or field.data == '': raise ValidationError(f'Specific type is required for {sub_type}') if field.data not in valid_specific_types: raise ValidationError(f'Invalid specific type for {sub_type}. Valid options are: {", ".join(valid_specific_types)}') def validate_type(self, field): stage = self.stage.data print(f"Validating type: {field.data} for stage: {stage}") if stage and stage in self.STAGE_TYPE_MAPPING: valid_types = self.STAGE_TYPE_MAPPING[stage] print(f"Valid types for {stage}: {valid_types}") if field.data not in valid_types and field.data != '': print(f"Invalid type: {field.data}") raise ValidationError(f'Invalid type for {stage} stage. Allowed types: {", ".join(valid_types)}') elif field.data != '': raise ValidationError('Please select a stage first') def validate_tooling_id(self, field): validate_tooling_id_format(self, field)