import_tada_member/app.py

213 lines
7.5 KiB
Python

import xmlrpc.client
import psycopg2
from psycopg2.extras import RealDictCursor
from flask import Flask, render_template, request, session, redirect, url_for, jsonify
from datetime import datetime, timedelta
app = Flask(__name__)
# Secret key for sessions
app.secret_key = 'super_secret_tada_migration_key_change_me_in_prod'
app.permanent_session_lifetime = timedelta(hours=8)
# --- Configurations ---
# PostgreSQL (Hardcoded as requested)
DB_HOST = "192.169.0.10"
DB_PORT = "5432"
DB_NAME = "postgres"
DB_USER = "postgres"
DB_PASS = "Mulut!23Berkomunikasi"
# Odoo 19
ODOO_URL = "http://localhost:1900"
ODOO_DB = "odoo19_OT_v3"
ODOO_USER = "admin"
ODOO_PASS = "admin"
def get_db_connection():
conn = psycopg2.connect(
host=DB_HOST,
port=DB_PORT,
dbname=DB_NAME,
user=DB_USER,
password=DB_PASS
)
return conn
@app.route('/')
def index():
if 'employee_id' not in session:
return redirect(url_for('login'))
return render_template('index.html', employee_id=session['employee_id'])
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
employee_id = request.form.get('employee_id')
if employee_id:
session.permanent = True
session['employee_id'] = employee_id
return redirect(url_for('index'))
return render_template('login.html')
@app.route('/logout')
def logout():
session.pop('employee_id', None)
return redirect(url_for('login'))
@app.route('/api/customers')
def get_customers():
if 'employee_id' not in session:
return jsonify({"error": "Unauthorized"}), 401
# DataTables parameters
draw = request.args.get('draw', type=int, default=1)
start = request.args.get('start', type=int, default=0)
length = request.args.get('length', type=int, default=10)
search_value = request.args.get('search[value]', default="")
order_column_index = request.args.get('order[0][column]', type=int, default=0)
order_dir = request.args.get('order[0][dir]', default='asc')
columns_map = ['id', 'name', 'phone_number', 'email', 'level', 'point_amount', 'responsible', 'total_spending']
order_column = columns_map[order_column_index] if order_column_index < len(columns_map) else 'id'
if order_dir not in ['asc', 'desc']:
order_dir = 'asc'
conn = None
try:
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=RealDictCursor)
# Base query
query = "SELECT * FROM tada_member"
count_query = "SELECT COUNT(*) FROM tada_member"
params = []
if search_value:
search_pattern = f"%{search_value}%"
where_clause = " WHERE name ILIKE %s OR phone_number ILIKE %s OR email ILIKE %s"
query += where_clause
count_query += where_clause
params.extend([search_pattern, search_pattern, search_pattern])
# Get total filtered count
cursor.execute(count_query, params)
total_filtered = cursor.fetchone()['count']
# Total records without filter
cursor.execute("SELECT COUNT(*) FROM tada_member")
total_records = cursor.fetchone()['count']
# Add pagination and sorting
query += f" ORDER BY {order_column} {order_dir.upper()} LIMIT %s OFFSET %s"
params.extend([length, start])
cursor.execute(query, params)
customers = cursor.fetchall()
# Convert date fields to string if any to allow JSON serialization
for row in customers:
if row.get('birthday'):
row['birthday'] = str(row['birthday'])
if row.get('updated_at'):
row['updated_at'] = str(row['updated_at'])
return jsonify({
"draw": draw,
"recordsTotal": total_records,
"recordsFiltered": total_filtered,
"data": customers
})
except Exception as e:
print(f"Error fetching customers: {e}")
return jsonify({"error": str(e)}), 500
finally:
if conn:
conn.close()
@app.route('/api/migrate/<int:customer_id>', methods=['POST'])
def migrate_customer(customer_id):
if 'employee_id' not in session:
return jsonify({"success": False, "message": "Unauthorized"}), 401
employee_id = session['employee_id']
conn = None
try:
# Fetch customer data
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("SELECT * FROM tada_member WHERE id = %s", (customer_id,))
customer = cursor.fetchone()
if not customer:
return jsonify({"success": False, "message": "Customer not found."}), 404
# Odoo connection
common = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/common')
uid = common.authenticate(ODOO_DB, ODOO_USER, ODOO_PASS, {})
if not uid:
return jsonify({"success": False, "message": "Failed to authenticate with Odoo."}), 500
models = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/object')
# 1. Find loyalty.program based on level
level = customer.get('level', '')
program_ids = models.execute_kw(ODOO_DB, uid, ODOO_PASS, 'loyalty.program', 'search', [[('name', 'ilike', level)]])
if not program_ids:
return jsonify({"success": False, "message": f"Loyalty program containing '{level}' not found in Odoo."}), 404
program_id = program_ids[0]
# Map gender safely (e.g. 'female' -> 'Female')
gender_val = customer.get('gender')
if isinstance(gender_val, str) and gender_val:
gender_val = gender_val.title()
# 2. Create res.partner
partner_data = {
'name': customer.get('name', ''),
'phone': customer.get('phone_number', ''),
'email': customer.get('email', ''),
'gender': gender_val or '',
'birth_date': str(customer.get('birthday', '')) if customer.get('birthday') else False,
'city': customer.get('city', ''),
'membership_level_id': program_id,
'total_spend': float(customer.get('total_spending') or 0.0)
}
# Replace None with False for Odoo XML-RPC compatibility
partner_data = {k: (v if v is not None else False) for k, v in partner_data.items()}
partner_id = models.execute_kw(ODOO_DB, uid, ODOO_PASS, 'res.partner', 'create', [partner_data])
# 3. Create loyalty.card
point_amount = customer.get('point_amount')
card_data = {
'partner_id': partner_id,
'program_id': program_id,
'points': float(point_amount) if point_amount is not None else 0.0
}
card_id = models.execute_kw(ODOO_DB, uid, ODOO_PASS, 'loyalty.card', 'create', [card_data])
# 4. Update tada_member
now = datetime.now()
cursor.execute("UPDATE tada_member SET responsible = %s, updated_at = %s WHERE id = %s", (employee_id, now, customer_id))
conn.commit()
return jsonify({"success": True, "message": "Migrasi data berhasil!"})
except Exception as e:
if conn:
conn.rollback()
print(f"Migration Error: {e}")
return jsonify({"success": False, "message": str(e)}), 500
finally:
if conn:
conn.close()
if __name__ == '__main__':
app.run(debug=True, port=5000, host='0.0.0.0')