125 lines
5.4 KiB
Python
125 lines
5.4 KiB
Python
from db import query_db, execute_db
|
|
from datetime import datetime
|
|
|
|
def execute_pipeline(actions, barcode, context):
|
|
"""
|
|
Executes the chain of actions defined in the Rule.
|
|
Returns: {'success': bool, 'message': str, 'data': dict}
|
|
"""
|
|
field_values = {}
|
|
should_save = False
|
|
|
|
for action in actions:
|
|
atype = action.get('type')
|
|
|
|
# --- MAP (Extract) ---
|
|
if atype == 'map':
|
|
start = int(action.get('start', 1)) - 1
|
|
end = int(action.get('end', len(barcode)))
|
|
target = action.get('field')
|
|
if target:
|
|
safe_end = min(end, len(barcode))
|
|
if start < len(barcode):
|
|
field_values[target] = barcode[start:safe_end]
|
|
|
|
# --- CLEAN (Format) ---
|
|
elif atype == 'clean':
|
|
target = action.get('field')
|
|
func = action.get('func')
|
|
if target in field_values:
|
|
val = str(field_values[target])
|
|
if func == 'TRIM': field_values[target] = val.strip()
|
|
elif func == 'REMOVE_SPACES': field_values[target] = val.replace(" ", "")
|
|
elif func == 'UPPERCASE': field_values[target] = val.upper()
|
|
elif func == 'REMOVE_LEADING_ZEROS': field_values[target] = val.lstrip('0')
|
|
|
|
# --- DUPLICATE CHECK (The Gatekeeper) ---
|
|
elif atype == 'duplicate':
|
|
target = action.get('field')
|
|
behavior = action.get('behavior', 'WARN') # Default to WARN
|
|
val = field_values.get(target)
|
|
|
|
if val:
|
|
# 1. Check DB
|
|
same_sess = query_db(f"SELECT id FROM {context['table_name']} WHERE {target} = ? AND session_id = ? AND is_deleted=0", [val, context['session_id']], one=True)
|
|
other_sess = query_db(f"SELECT id FROM {context['table_name']} WHERE {target} = ? AND is_deleted=0", [val], one=True)
|
|
|
|
is_dup = False
|
|
dup_msg = ""
|
|
|
|
if same_sess:
|
|
is_dup = True
|
|
dup_msg = f"Already scanned in THIS session ({val})"
|
|
field_values['duplicate_status'] = 'dup_same_session'
|
|
field_values['duplicate_info'] = 'Duplicate in same session'
|
|
elif other_sess:
|
|
is_dup = True
|
|
dup_msg = f"Previously scanned in another session ({val})"
|
|
field_values['duplicate_status'] = 'dup_other_session'
|
|
field_values['duplicate_info'] = 'Duplicate from history'
|
|
else:
|
|
field_values['duplicate_status'] = 'normal'
|
|
field_values['duplicate_info'] = None
|
|
|
|
# 2. Enforce Behavior
|
|
if is_dup:
|
|
if behavior == 'BLOCK':
|
|
# STRICT MODE: Stop immediately.
|
|
return {
|
|
'success': False,
|
|
'message': f"⛔ STRICT MODE: {dup_msg}. Entry denied.",
|
|
'data': field_values
|
|
}
|
|
|
|
elif behavior == 'WARN':
|
|
# WARN MODE: Ask user, unless they already clicked "Yes"
|
|
if not context.get('confirm_duplicate'):
|
|
return {
|
|
'success': False,
|
|
'needs_confirmation': True,
|
|
'message': f"⚠️ {dup_msg}",
|
|
'data': field_values
|
|
}
|
|
# --- USER INPUT (The Gatekeeper) ---
|
|
elif atype == 'input':
|
|
# 1. Check if we received the manual data (Weight) from the Save button
|
|
incoming_data = context.get('extra_data')
|
|
|
|
# 2. If data exists, MERGE it and CONTINUE (Don't stop!)
|
|
if incoming_data:
|
|
# Update our main data list with the user's input (e.g. weight=164)
|
|
field_values.update(incoming_data)
|
|
continue # <--- RESUME PIPELINE (Goes to next rule, usually SAVE)
|
|
|
|
# 3. If no data, STOP and ask for it
|
|
return {
|
|
'success': False,
|
|
'needs_input': True,
|
|
'message': 'Opening Details Form...',
|
|
'data': field_values
|
|
}
|
|
|
|
# --- SAVE MARKER ---
|
|
elif atype == 'save':
|
|
should_save = True
|
|
|
|
# --- RESULT ---
|
|
if should_save:
|
|
try:
|
|
# Commit to DB
|
|
cols = ['session_id', 'scanned_by', 'scanned_at']
|
|
vals = [context['session_id'], context['user_id'], datetime.now()]
|
|
|
|
for k, v in field_values.items():
|
|
cols.append(k)
|
|
vals.append(v)
|
|
|
|
placeholders = ', '.join(['?'] * len(cols))
|
|
sql = f"INSERT INTO {context['table_name']} ({', '.join(cols)}) VALUES ({placeholders})"
|
|
new_id = execute_db(sql, vals)
|
|
|
|
return {'success': True, 'message': 'Saved Successfully', 'detail_id': new_id, 'data': field_values}
|
|
except Exception as e:
|
|
return {'success': False, 'message': f"Database Error: {str(e)}", 'data': field_values}
|
|
else:
|
|
return {'success': True, 'message': f"✅ Parsed: {field_values} (No Save Action)", 'data': field_values} |