developing

This commit is contained in:
wystan_rin 2024-11-13 15:55:17 +08:00
parent c31591484c
commit 30be8c72df
36 changed files with 305 additions and 60 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

14
.idea/deployment.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="root@192.168.16.207:22 password">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
</project>

13
.idea/payment.iml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="Flask">
<option name="enabled" value="true" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
</component>
</module>

7
.idea/vcs.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/payment_headend" vcs="Git" />
</component>
</project>

7
app.py
View File

@ -1,7 +0,0 @@
from flask import Flask
from config import get_config
config = get_config()
app = Flask(__name__)

42
payment_backend/app.py Normal file
View File

@ -0,0 +1,42 @@
from flask import Flask, request, jsonify
from config import get_config
from services.order import OrderService
config = get_config()
app = Flask(__name__)
order_service = OrderService() # 获取单例实例
@app.route('/createOrder', methods=['POST'])
def create_order():
data = request.get_json()
phone = data.get('phone', None)
email = data.get('email', None)
address = data.get('address', None)
try:
payment_method = data['paymentMethod']
except KeyError:
return jsonify({
"message": "Unsupported payment method. Currently, only USDT payments are supported."
}), 400
addresses = order_service.get_user_addresses(phone, email, address, payment_method)
if not addresses:
return jsonify({
"message": "No payment address associated with you was found. Please provide a payment address."
}), 400
if len(addresses) == 1:
order_id = order_service.create_order(addresses[0])
return jsonify({"order_id": order_id}), 200
# 多个地址的情况
return jsonify({
"message": "请选择一个地址进行下单。",
"addresses": addresses
}), 200
if __name__ == '__main__':
app.run(debug=True)

View File

@ -10,3 +10,4 @@ password: 'your_mysql_password'
host: 'localhost' host: 'localhost'
database: 'your_database_name' database: 'your_database_name'
autocommit: false autocommit: false
allow_multi_statements: True

93
payment_backend/models.py Normal file
View File

@ -0,0 +1,93 @@
from utils.database import pack_params
class User:
def __init__(self, id_=None, name=None, phone=None, email=None, address=None, payment_method=None):
self.id = id_
self.name = name
self.phone = phone
self.email = email
self.address = address
self.payment_method = payment_method
def insert_sql(self, params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}", join_str=",",
name=self.name, phone=self.phone, email=self.email, address=self.address,
payment_method=self.payment_method)
return f"INSERT INTO user ({params_sql}) VALUES ({','.join('%s' for _ in params)})", params
def select_sql(self, condition="AND", params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ",
name=self.name, phone=self.phone, email=self.email, address=self.address,
payment_method=self.payment_method)
return f"SELECT id, name, phone, email, address, payment_method FROM user WHERE {params_sql}", params
def exists_sql(self, condition="AND", params_format="list"):
params_sql, params = pack_params(params_format=params_format, param_sql="{param}=%s", join_str=f" {condition} ",
name=self.name, phone=self.phone, email=self.email, address=self.address,
payment_method=self.payment_method)
return f"SELECT id FROM user WHERE {params_sql} LIMIT 1", params
def params(self, format="dict"):
if format == "list":
params = []
elif format == "dict":
params = {}
else:
raise ValueError("format must be list or dict")
if self.uid:
if format == "list":
params.append(self.uid)
elif format == "dict":
params["uid"] = self.uid
if self.name:
if format == "list":
params.append(self.name)
elif format == "dict":
params["name"] = self.name
if self.phone:
if format == "list":
params.append(self.phone)
elif format == "dict":
params["phone"] = self.phone
if self.email:
if format == "list":
params.append(self.email)
elif format == "dict":
params["email"] = self.email
if self.address:
if format == "list":
params.append(self.address)
elif format == "dict":
params["address"] = self.address
if self.payment_method:
if format == "list":
params.append(self.payment_method)
elif format == "dict":
params["payment_method"] = self.payment_method
return params
def get_difference(self, other_user):
different_attrs = {}
if self.uid != other_user.uid:
different_attrs["uid"] = (self.uid, other_user.uid)
if self.name != other_user.name:
different_attrs["name"] = (self.name, other_user.name)
if self.phone != other_user.phone:
different_attrs["phone"] = (self.phone, other_user.phone)
if self.email != other_user.email:
different_attrs["email"] = (self.email, other_user.email)
if self.address != other_user.address:
different_attrs["address"] = (self.address, other_user.address)
if self.payment_method != other_user.payment_method:
different_attrs["payment_method"] = (self.payment_method, other_user.payment_method)
return different_attrs
def __eq__(self, other):
if isinstance(other, User):
return ((self.name, self.phone, self.email, self.address, self.payment_method)
== (other.name, other.phone, other.email, other.address, other.payment_method))
return False
def __hash__(self):
return hash((self.name, self.phone, self.email, self.address, self.payment_method))

View File

@ -0,0 +1,74 @@
import itertools
from custom_decorators import singleton
from database import Database
from models import User
@singleton
class UserRepository:
def __init__(self, config):
self.db = Database(config['MYSQL'])
def get_or_create(self, user):
users = []
cursor = self.db.execute_query(*user.select_sql(condition="OR"))
same_users = cursor.fetchall()
new_user = not len(same_users)
# 对用户已存在的属性判断是否有新属性
update_user = set()
update_sqls = []
update_params_list = []
delete_params = []
exist_conflicting_attr = False
for same_user in same_users:
exist_conflicting_attr = False
different_attrs = user.get_difference(same_user)
# 用于判断是否有新属性
update_sql_params = []
update_params = []
for k, v in different_attrs.items():
new_attr, exist_attr = v
if exist_attr is None:
setattr(same_user, k, new_attr)
update_sql_params.append(f"{k}=%s")
update_params.append(new_attr)
else:
# 出现冲突的属性,考虑新增一行记录
exist_conflicting_attr = True
break
if same_user in update_user:
delete_params.append((same_user.id,))
else:
users.append(same_user)
exist_new_attr = bool(update_params)
if exist_new_attr:
update_user.add(same_user)
update_sqls.append(f'UPDATE user SET {",".join(update_sql_params)} WHERE id=%s;')
update_params.append(same_user.id)
update_params_list.append(update_params)
sql_flag = False
try:
if delete_params:
sql_flag = True
self.db.get_connection().cursor().executemany("DELETE FROM user WHERE id=%s", delete_params)
if update_user:
sql_flag = True
self.db.get_connection().cursor().execute("".join(update_sqls),
list(itertools.chain.from_iterable(update_params_list)),
multi=True)
if sql_flag:
self.db.commit()
except Exception:
self.db.rollback()
raise
if new_user or exist_conflicting_attr:
try:
self.db.execute_query(*user.insert_sql())
self.db.commit()
except Exception:
self.db.rollback()
raise
users.append(user)
return users

View File

@ -1,7 +1,9 @@
import uuid import uuid
from custom_decorators import singleton from custom_decorators import singleton
from models import User
from repositories.order import OrderRepository from repositories.order import OrderRepository
from repositories.user import UserRepository
from services.payment import PaymentService from services.payment import PaymentService
from utils.datetime import current, current_timestamp, is_time_difference_greater_than from utils.datetime import current, current_timestamp, is_time_difference_greater_than
@ -9,14 +11,27 @@ from utils.datetime import current, current_timestamp, is_time_difference_greate
@singleton @singleton
class OrderService: class OrderService:
def __init__(self, config): def __init__(self, config):
self.order_repo = OrderRepository(config) self.config = config
self.payment_service = PaymentService() self.payment_service = PaymentService()
self.order_repo = OrderRepository(config)
self.user_repo = UserRepository(config)
def create_order(self, from_address, to_address): def get_user_addresses(self, phone=None, email=None, address=None, payment_method=None):
if address is None:
if phone or email:
users = self.user_repo.get_or_create(User(phone=phone, email=email))
addresses = set(user.address for user in users if address)
return list(addresses)
raise ValueError('A phone number, email, or address is required.')
return [address]
def create_order(self, address=None):
date_str = current().strftime('%Y%m%d%H%M%S') date_str = current().strftime('%Y%m%d%H%M%S')
unique_id = str(uuid.uuid4()).split('-')[0] unique_id = str(uuid.uuid4()).split('-')[0]
order_id = f"{date_str}-{unique_id}" order_id = f"{date_str}-{unique_id}"
self.order_repo.create(order_id, from_address, to_address)
self.order_repo.create(order_id, address,
self.config['PaymentAddresses'])
return order_id return order_id
def finish_order(self, order_id): def finish_order(self, order_id):

View File

@ -0,0 +1,16 @@
def pack_params(params_format="list", param_sql="{param}=%s", join_str=" AND ", **kwargs):
if params_format == "list":
params = []
elif params_format == "dict":
params = {}
else:
raise ValueError("Unknown params format")
param_sqls = []
for k, v in kwargs.items():
if v is not None:
if params_format == "list":
params.append(v)
elif params_format == "dict":
params[k] = v
param_sqls.append(param_sql.format(param=k))
return join_str.join(param_sqls), params

View File

@ -1,40 +0,0 @@
from custom_decorators import singleton
from database import Database
from utils.database import pack_params
@singleton
class UserRepository:
def __init__(self, config):
self.db = Database(config['MYSQL'])
def get_user(self, phone=None, email=None, address=None):
params_sql, params = pack_params(phone=phone, email=email, address=address)
sql = f"SELECT name, phone, email, address FROM user WHERE {params_sql}"
cursor = self.db.execute_query(sql, params)
users = cursor.fetchall()
return users
def create_user(self, phone=None, email=None, address=None):
_, params = pack_params(phone=phone, email=email, address=address)
sql = f"INSERT INTO user (phone, email, address) VALUES (%s, %s, %s)"
self.db.execute_query(sql, params)
self.db.commit()
def record_exists(self, phone=None, email=None, address=None):
params_sql, params = pack_params(phone=phone, email=email, address=address)
sql = f"SELECT EXISTS(SELECT 1 FROM user WHERE {params_sql} LIMIT 1)"
cursor = self.db.execute_query(sql, params)
result = cursor.fetchone()
return bool(result[0])
def create_if_not_exists(self, phone=None, email=None, address=None):
if not self.record_exists(phone=phone, email=email, address=address):
self.create_user(phone=phone, email=email, address=address)
def get_and_create_if_not_exists(self, phone=None, email=None, address=None):
users = self.get_user(phone=phone, email=email, address=address)
if len(users) == 0:
self.create_user(phone=phone, email=email, address=address)
else:
return users

View File

@ -1,10 +0,0 @@
def pack_params(**kwargs):
params = []
param_sqls = []
flag = False
for k, v in kwargs.items():
flag = True
params.append(v)
param_sqls.append(f"{k}=%s")
if flag:
return " AND ".join(param_sqls), params