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'
database: 'your_database_name'
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
from custom_decorators import singleton
from models import User
from repositories.order import OrderRepository
from repositories.user import UserRepository
from services.payment import PaymentService
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
class OrderService:
def __init__(self, config):
self.order_repo = OrderRepository(config)
self.config = config
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')
unique_id = str(uuid.uuid4()).split('-')[0]
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
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