6c0d5a4e63
- Flask-based mold cost calculation application - PostgreSQL database with SQLAlchemy ORM - Docker/Podman containerization - Comprehensive documentation in docs/ - Clean, organized codebase without obsolete files - Production-ready deployment configuration - Enhanced pytest configuration with coverage reporting - Master/Development branch structure
193 lines
8.0 KiB
Python
193 lines
8.0 KiB
Python
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) |