Add MOC generator with leading zeros support (MOC-0001 format)
This commit is contained in:
144
app/services/moc_generator_updated.py
Normal file
144
app/services/moc_generator_updated.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""MOC Number Generator Service
|
||||
|
||||
Handles automatic generation and validation of MOC (My Own Creation) set numbers.
|
||||
"""
|
||||
|
||||
from app.models import Set
|
||||
from app import db
|
||||
|
||||
|
||||
class MOCNumberGenerator:
|
||||
"""Service for generating sequential MOC numbers with leading zeros"""
|
||||
|
||||
DEFAULT_PREFIX = 'MOC'
|
||||
DEFAULT_START = 1 # Start from 1 for MOC-0001, MOC-0002, etc.
|
||||
NUMBER_PADDING = 4 # Format as 4 digits with leading zeros (0001, 0002, etc.)
|
||||
|
||||
@staticmethod
|
||||
def generate_next_number(prefix='MOC', user_id=None):
|
||||
"""
|
||||
Generate the next available MOC number with leading zeros.
|
||||
|
||||
Format: MOC-0001, MOC-0002, MOC-0003, etc.
|
||||
|
||||
Args:
|
||||
prefix (str): MOC prefix (default: 'MOC')
|
||||
user_id (int, optional): User ID for user-scoped numbering.
|
||||
None for global numbering (default).
|
||||
|
||||
Returns:
|
||||
str: Next MOC number (e.g., 'MOC-0012')
|
||||
|
||||
Examples:
|
||||
>>> MOCNumberGenerator.generate_next_number()
|
||||
'MOC-0001'
|
||||
>>> MOCNumberGenerator.generate_next_number(prefix='CUSTOM')
|
||||
'CUSTOM-0001'
|
||||
"""
|
||||
try:
|
||||
# Build query for existing MOC numbers with this prefix
|
||||
query = Set.query.filter(
|
||||
Set.is_moc == True,
|
||||
Set.set_number.like(f'{prefix}-%')
|
||||
)
|
||||
|
||||
# Add user filter if user-scoped
|
||||
if user_id is not None:
|
||||
query = query.filter(Set.user_id == user_id)
|
||||
|
||||
# Get the highest existing MOC number
|
||||
latest_set = query.order_by(Set.set_number.desc()).first()
|
||||
|
||||
if latest_set:
|
||||
# Extract the number from the set_number (e.g., "MOC-0012" -> 12)
|
||||
try:
|
||||
number_part = latest_set.set_number.split('-')[-1]
|
||||
current_num = int(number_part)
|
||||
next_num = current_num + 1
|
||||
except (ValueError, IndexError):
|
||||
# If parsing fails, start from default
|
||||
next_num = MOCNumberGenerator.DEFAULT_START
|
||||
else:
|
||||
# No existing MOCs, start from default
|
||||
next_num = MOCNumberGenerator.DEFAULT_START
|
||||
|
||||
# Format with leading zeros (e.g., 12 -> "0012")
|
||||
formatted_number = str(next_num).zfill(MOCNumberGenerator.NUMBER_PADDING)
|
||||
|
||||
return f'{prefix}-{formatted_number}'
|
||||
|
||||
except Exception as e:
|
||||
# On any error, return a safe default
|
||||
formatted_default = str(MOCNumberGenerator.DEFAULT_START).zfill(
|
||||
MOCNumberGenerator.NUMBER_PADDING
|
||||
)
|
||||
return f'{prefix}-{formatted_default}'
|
||||
|
||||
@staticmethod
|
||||
def validate_moc_number(set_number, user_id=None):
|
||||
"""
|
||||
Check if a MOC number is available (not already in use).
|
||||
|
||||
Args:
|
||||
set_number (str): MOC number to validate
|
||||
user_id (int, optional): User ID for user-scoped validation.
|
||||
None for global validation.
|
||||
|
||||
Returns:
|
||||
bool: True if available, False if already exists
|
||||
|
||||
Examples:
|
||||
>>> MOCNumberGenerator.validate_moc_number('MOC-0012')
|
||||
True
|
||||
>>> MOCNumberGenerator.validate_moc_number('MOC-0001') # If exists
|
||||
False
|
||||
"""
|
||||
query = Set.query.filter(
|
||||
Set.is_moc == True,
|
||||
Set.set_number == set_number
|
||||
)
|
||||
|
||||
# Add user filter if user-scoped
|
||||
if user_id is not None:
|
||||
query = query.filter(Set.user_id == user_id)
|
||||
|
||||
existing = query.first()
|
||||
return existing is None # Available if no existing set found
|
||||
|
||||
@staticmethod
|
||||
def is_moc_number(set_number, prefix='MOC'):
|
||||
"""
|
||||
Check if a set number follows the MOC format.
|
||||
|
||||
Format: PREFIX-NNNN (where NNNN is 4 digits with leading zeros)
|
||||
|
||||
Args:
|
||||
set_number (str): Set number to check
|
||||
prefix (str): Expected prefix (default: 'MOC')
|
||||
|
||||
Returns:
|
||||
bool: True if matches MOC format, False otherwise
|
||||
|
||||
Examples:
|
||||
>>> MOCNumberGenerator.is_moc_number('MOC-0012')
|
||||
True
|
||||
>>> MOCNumberGenerator.is_moc_number('10497')
|
||||
False
|
||||
>>> MOCNumberGenerator.is_moc_number('CUSTOM-0001', prefix='CUSTOM')
|
||||
True
|
||||
"""
|
||||
if not set_number or not isinstance(set_number, str):
|
||||
return False
|
||||
|
||||
# Check if it starts with the prefix followed by a hyphen
|
||||
if not set_number.startswith(f'{prefix}-'):
|
||||
return False
|
||||
|
||||
# Extract the number part
|
||||
try:
|
||||
number_part = set_number.split('-', 1)[1]
|
||||
# Check if it's a valid number (will work with or without leading zeros)
|
||||
int(number_part)
|
||||
return True
|
||||
except (ValueError, IndexError):
|
||||
return False
|
||||
Reference in New Issue
Block a user