diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -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
diff --git a/.idea/deployment.xml b/.idea/deployment.xml
new file mode 100644
index 0000000..4f73c50
--- /dev/null
+++ b/.idea/deployment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..a6218fe
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/payment.iml b/.idea/payment.iml
new file mode 100644
index 0000000..f617e98
--- /dev/null
+++ b/.idea/payment.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..a171b33
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app.py b/app.py
deleted file mode 100644
index 8b3525b..0000000
--- a/app.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from flask import Flask
-
-from config import get_config
-
-config = get_config()
-
-app = Flask(__name__)
diff --git a/.gitignore b/payment_backend/.gitignore
similarity index 100%
rename from .gitignore
rename to payment_backend/.gitignore
diff --git a/README.md b/payment_backend/README.md
similarity index 100%
rename from README.md
rename to payment_backend/README.md
diff --git a/__init__.py b/payment_backend/__init__.py
similarity index 100%
rename from __init__.py
rename to payment_backend/__init__.py
diff --git a/api/__init__.py b/payment_backend/api/__init__.py
similarity index 100%
rename from api/__init__.py
rename to payment_backend/api/__init__.py
diff --git a/api/tronscan.py b/payment_backend/api/tronscan.py
similarity index 100%
rename from api/tronscan.py
rename to payment_backend/api/tronscan.py
diff --git a/payment_backend/app.py b/payment_backend/app.py
new file mode 100644
index 0000000..48aa46c
--- /dev/null
+++ b/payment_backend/app.py
@@ -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)
diff --git a/config/__init__.py b/payment_backend/config/__init__.py
similarity index 100%
rename from config/__init__.py
rename to payment_backend/config/__init__.py
diff --git a/config/db.py b/payment_backend/config/db.py
similarity index 100%
rename from config/db.py
rename to payment_backend/config/db.py
diff --git a/config/param.ini b/payment_backend/config/param.ini
similarity index 89%
rename from config/param.ini
rename to payment_backend/config/param.ini
index 42a7e9c..93bc4de 100644
--- a/config/param.ini
+++ b/payment_backend/config/param.ini
@@ -10,3 +10,4 @@ password: 'your_mysql_password'
host: 'localhost'
database: 'your_database_name'
autocommit: false
+allow_multi_statements: True
\ No newline at end of file
diff --git a/config/utils.py b/payment_backend/config/utils.py
similarity index 100%
rename from config/utils.py
rename to payment_backend/config/utils.py
diff --git a/custom_decorators.py b/payment_backend/custom_decorators.py
similarity index 100%
rename from custom_decorators.py
rename to payment_backend/custom_decorators.py
diff --git a/database.py b/payment_backend/database.py
similarity index 100%
rename from database.py
rename to payment_backend/database.py
diff --git a/payment_backend/models.py b/payment_backend/models.py
new file mode 100644
index 0000000..1dd08ea
--- /dev/null
+++ b/payment_backend/models.py
@@ -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))
diff --git a/repositories/__init__.py b/payment_backend/repositories/__init__.py
similarity index 100%
rename from repositories/__init__.py
rename to payment_backend/repositories/__init__.py
diff --git a/repositories/order.py b/payment_backend/repositories/order.py
similarity index 100%
rename from repositories/order.py
rename to payment_backend/repositories/order.py
diff --git a/payment_backend/repositories/user.py b/payment_backend/repositories/user.py
new file mode 100644
index 0000000..b580fdc
--- /dev/null
+++ b/payment_backend/repositories/user.py
@@ -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
diff --git a/requirements.txt b/payment_backend/requirements.txt
similarity index 100%
rename from requirements.txt
rename to payment_backend/requirements.txt
diff --git a/services/__init__.py b/payment_backend/services/__init__.py
similarity index 100%
rename from services/__init__.py
rename to payment_backend/services/__init__.py
diff --git a/services/order.py b/payment_backend/services/order.py
similarity index 66%
rename from services/order.py
rename to payment_backend/services/order.py
index b86a9a9..1272db4 100644
--- a/services/order.py
+++ b/payment_backend/services/order.py
@@ -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):
diff --git a/services/payment.py b/payment_backend/services/payment.py
similarity index 100%
rename from services/payment.py
rename to payment_backend/services/payment.py
diff --git a/services/user.py b/payment_backend/services/user.py
similarity index 100%
rename from services/user.py
rename to payment_backend/services/user.py
diff --git a/tests/test_tronscan.py b/payment_backend/tests/test_tronscan.py
similarity index 100%
rename from tests/test_tronscan.py
rename to payment_backend/tests/test_tronscan.py
diff --git a/utils/__init__.py b/payment_backend/utils/__init__.py
similarity index 100%
rename from utils/__init__.py
rename to payment_backend/utils/__init__.py
diff --git a/payment_backend/utils/database.py b/payment_backend/utils/database.py
new file mode 100644
index 0000000..f173ff3
--- /dev/null
+++ b/payment_backend/utils/database.py
@@ -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
diff --git a/utils/datetime.py b/payment_backend/utils/datetime.py
similarity index 100%
rename from utils/datetime.py
rename to payment_backend/utils/datetime.py
diff --git a/utils/tronscan.py b/payment_backend/utils/tronscan.py
similarity index 100%
rename from utils/tronscan.py
rename to payment_backend/utils/tronscan.py
diff --git a/repositories/user.py b/repositories/user.py
deleted file mode 100644
index 4eec1e9..0000000
--- a/repositories/user.py
+++ /dev/null
@@ -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
diff --git a/utils/database.py b/utils/database.py
deleted file mode 100644
index 128d6a5..0000000
--- a/utils/database.py
+++ /dev/null
@@ -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