python学习
This commit is contained in:
817
.idea/workspace.xml
generated
817
.idea/workspace.xml
generated
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,6 @@ def iPagination( params ):
|
||||
ret['range'] = range( ret['from'],ret['end'] + 1 )
|
||||
return ret
|
||||
|
||||
|
||||
'''
|
||||
统一渲染方法
|
||||
'''
|
||||
@@ -108,7 +107,7 @@ def selectFilterObj( obj,field ):
|
||||
return ret
|
||||
|
||||
|
||||
def getDictFilterField( db_model,select_filed,key_field,id_list ):
|
||||
def getDictListFilterField( db_model,select_filed,key_field,id_list ):
|
||||
ret = {}
|
||||
query = db_model.query
|
||||
if id_list and len( id_list ) > 0:
|
||||
|
||||
35
common/libs/member/CartService.py
Normal file
35
common/libs/member/CartService.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import hashlib,requests,random,string,json
|
||||
from application import app,db
|
||||
from common.models.member.MemberCart import MemberCart
|
||||
from common.libs.Helper import getCurrentDate
|
||||
class CartService():
|
||||
|
||||
@staticmethod
|
||||
def deleteItem( member_id = 0,items = None ):
|
||||
if member_id < 1 or not items:
|
||||
return False
|
||||
for item in items:
|
||||
MemberCart.query.filter_by( food_id = item['id'],member_id = member_id ).delete()
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def setItems( member_id = 0,food_id = 0,number = 0 ):
|
||||
if member_id < 1 or food_id < 1 or number < 1:
|
||||
return False
|
||||
cart_info = MemberCart.query.filter_by( food_id = food_id, member_id= member_id ).first()
|
||||
if cart_info:
|
||||
model_cart = cart_info
|
||||
else:
|
||||
model_cart = MemberCart()
|
||||
model_cart.member_id = member_id
|
||||
model_cart.created_time = getCurrentDate()
|
||||
|
||||
model_cart.food_id = food_id
|
||||
model_cart.quantity = number
|
||||
model_cart.updated_time = getCurrentDate()
|
||||
db.session.add(model_cart)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
191
common/libs/pay/PayService.py
Normal file
191
common/libs/pay/PayService.py
Normal file
@@ -0,0 +1,191 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import hashlib,time,random,decimal,json
|
||||
from application import app,db
|
||||
from common.models.food.Food import Food
|
||||
from common.models.food.FoodSaleChangeLog import FoodSaleChangeLog
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.models.pay.PayOrderItem import PayOrderItem
|
||||
from common.models.pay.PayOrderCallbackData import PayOrderCallbackData
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from common.libs.queue.QueueService import QueueService
|
||||
from common.libs.food.FoodService import FoodService
|
||||
class PayService():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def createOrder(self,member_id,items = None,params = None):
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
pay_price = decimal.Decimal( 0.00 )
|
||||
continue_cnt = 0
|
||||
food_ids = []
|
||||
for item in items:
|
||||
if decimal.Decimal( item['price'] ) < 0 :
|
||||
continue_cnt += 1
|
||||
continue
|
||||
|
||||
pay_price = pay_price + decimal.Decimal( item['price'] ) * int( item['number'] )
|
||||
food_ids.append( item['id'] )
|
||||
|
||||
if continue_cnt >= len(items ) :
|
||||
resp['code'] = -1
|
||||
resp['msg'] = '商品items为空~~'
|
||||
return resp
|
||||
|
||||
yun_price = params['yun_price'] if params and 'yun_price' in params else 0
|
||||
note = params['note'] if params and 'note' in params else ''
|
||||
express_address_id = params['express_address_id'] if params and 'express_address_id' in params else 0
|
||||
express_info = params['express_info'] if params and 'express_info' in params else {}
|
||||
yun_price = decimal.Decimal( yun_price )
|
||||
total_price = pay_price + yun_price
|
||||
try:
|
||||
#为了防止并发库存出问题了,我们坐下selectfor update, 这里可以给大家演示下
|
||||
tmp_food_list = db.session.query( Food ).filter( Food.id.in_( food_ids ) )\
|
||||
.with_for_update().all()
|
||||
|
||||
tmp_food_stock_mapping = {}
|
||||
for tmp_item in tmp_food_list:
|
||||
tmp_food_stock_mapping[ tmp_item.id ] = tmp_item.stock
|
||||
|
||||
model_pay_order = PayOrder()
|
||||
model_pay_order.order_sn = self.geneOrderSn()
|
||||
model_pay_order.member_id = member_id
|
||||
model_pay_order.total_price = total_price
|
||||
model_pay_order.yun_price = yun_price
|
||||
model_pay_order.pay_price = pay_price
|
||||
model_pay_order.note = note
|
||||
model_pay_order.status = -8
|
||||
model_pay_order.express_status = -8
|
||||
model_pay_order.express_address_id = express_address_id
|
||||
model_pay_order.express_info = json.dumps( express_info )
|
||||
model_pay_order.updated_time = model_pay_order.created_time = getCurrentDate()
|
||||
db.session.add( model_pay_order )
|
||||
#db.session.flush()
|
||||
for item in items:
|
||||
tmp_left_stock = tmp_food_stock_mapping[ item['id'] ]
|
||||
|
||||
if decimal.Decimal(item['price']) < 0:
|
||||
continue
|
||||
|
||||
if int( item['number'] ) > int( tmp_left_stock ):
|
||||
raise Exception( "您购买的这美食太火爆了,剩余:%s,你购买%s~~"%( tmp_left_stock,item['number'] ) )
|
||||
|
||||
tmp_ret = Food.query.filter_by( id = item['id'] ).update({
|
||||
"stock":int(tmp_left_stock) - int(item['number'])
|
||||
})
|
||||
if not tmp_ret:
|
||||
raise Exception("下单失败请重新下单")
|
||||
|
||||
tmp_pay_item = PayOrderItem()
|
||||
tmp_pay_item.pay_order_id = model_pay_order.id
|
||||
tmp_pay_item.member_id = member_id
|
||||
tmp_pay_item.quantity = item['number']
|
||||
tmp_pay_item.price = item['price']
|
||||
tmp_pay_item.food_id = item['id']
|
||||
tmp_pay_item.note = note
|
||||
tmp_pay_item.updated_time = tmp_pay_item.created_time = getCurrentDate()
|
||||
db.session.add( tmp_pay_item )
|
||||
#db.session.flush()
|
||||
|
||||
FoodService.setStockChangeLog( item['id'],-item['number'],"在线购买" )
|
||||
db.session.commit()
|
||||
resp['data'] = {
|
||||
'id' : model_pay_order.id,
|
||||
'order_sn' : model_pay_order.order_sn,
|
||||
'total_price':str( total_price )
|
||||
}
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
print( e )
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "下单失败请重新下单"
|
||||
resp['msg'] = str(e)
|
||||
return resp
|
||||
return resp
|
||||
|
||||
def closeOrder(self,pay_order_id = 0):
|
||||
if pay_order_id < 1:
|
||||
return False
|
||||
pay_order_info = PayOrder.query.filter_by( id = pay_order_id ,status = -8 ).first()
|
||||
if not pay_order_info:
|
||||
return False
|
||||
|
||||
pay_order_items = PayOrderItem.query.filter_by( pay_order_id = pay_order_id ).all()
|
||||
if pay_order_items:
|
||||
#需要归还库存
|
||||
for item in pay_order_items:
|
||||
tmp_food_info = Food.query.filter_by( id = item.food_id ).first()
|
||||
if tmp_food_info:
|
||||
tmp_food_info.stock = tmp_food_info.stock + item.quantity
|
||||
tmp_food_info.updated_time = getCurrentDate()
|
||||
db.session.add( tmp_food_info )
|
||||
db.session.commit()
|
||||
FoodService.setStockChangeLog( item.food_id, item.quantity, "订单取消")
|
||||
|
||||
pay_order_info.status = 0
|
||||
pay_order_info.updated_time = getCurrentDate()
|
||||
db.session.add( pay_order_info )
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
def orderSuccess(self,pay_order_id = 0,params = None):
|
||||
try:
|
||||
pay_order_info = PayOrder.query.filter_by( id = pay_order_id ).first()
|
||||
if not pay_order_info or pay_order_info.status not in [ -8,-7 ]:
|
||||
return True
|
||||
|
||||
pay_order_info.pay_sn = params['pay_sn'] if params and 'pay_sn' in params else ''
|
||||
pay_order_info.status = 1
|
||||
pay_order_info.express_status = -7
|
||||
pay_order_info.updated_time = getCurrentDate()
|
||||
db.session.add( pay_order_info )
|
||||
|
||||
|
||||
pay_order_items = PayOrderItem.query.filter_by( pay_order_id = pay_order_id ).all()
|
||||
for order_item in pay_order_items:
|
||||
tmp_model_sale_log = FoodSaleChangeLog()
|
||||
tmp_model_sale_log.food_id = order_item.food_id
|
||||
tmp_model_sale_log.quantity = order_item.quantity
|
||||
tmp_model_sale_log.price = order_item.price
|
||||
tmp_model_sale_log.member_id = order_item.member_id
|
||||
tmp_model_sale_log.created_time = getCurrentDate()
|
||||
db.session.add( tmp_model_sale_log )
|
||||
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
print(e)
|
||||
return False
|
||||
|
||||
#加入通知队列,做消息提醒和
|
||||
QueueService.addQueue( "pay",{
|
||||
"member_id": pay_order_info.member_id,
|
||||
"pay_order_id":pay_order_info.id
|
||||
})
|
||||
return True
|
||||
|
||||
def addPayCallbackData(self,pay_order_id = 0,type = 'pay',data = ''):
|
||||
model_callback = PayOrderCallbackData()
|
||||
model_callback.pay_order_id = pay_order_id
|
||||
if type == "pay":
|
||||
model_callback.pay_data = data
|
||||
model_callback.refund_data = ''
|
||||
else:
|
||||
model_callback.refund_data = data
|
||||
model_callback.pay_data = ''
|
||||
|
||||
model_callback.created_time = model_callback.updated_time = getCurrentDate()
|
||||
db.session.add( model_callback )
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
def geneOrderSn(self):
|
||||
m = hashlib.md5()
|
||||
sn = None
|
||||
while True:
|
||||
str = "%s-%s"%( int( round( time.time() * 1000) ),random.randint( 0,9999999 ) )
|
||||
m.update(str.encode("utf-8"))
|
||||
sn = m.hexdigest()
|
||||
if not PayOrder.query.filter_by( order_sn = sn ).first():
|
||||
break
|
||||
return sn
|
||||
113
common/libs/pay/WeChatService.py
Normal file
113
common/libs/pay/WeChatService.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import hashlib,requests,uuid,json,datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
from application import app,db
|
||||
from common.models.pay.OauthAccessToken import OauthAccessToken
|
||||
from common.libs.Helper import getCurrentDate
|
||||
class WeChatService():
|
||||
|
||||
def __init__(self,merchant_key = None):
|
||||
self.merchant_key = merchant_key
|
||||
|
||||
def create_sign(self, pay_data):
|
||||
'''
|
||||
生成签名
|
||||
:return:
|
||||
'''
|
||||
stringA = '&'.join(["{0}={1}".format(k, pay_data.get(k)) for k in sorted(pay_data)])
|
||||
stringSignTemp = '{0}&key={1}'.format(stringA, self.merchant_key)
|
||||
sign = hashlib.md5( stringSignTemp.encode("utf-8") ).hexdigest()
|
||||
return sign.upper()
|
||||
|
||||
def get_pay_info(self,pay_data = None):
|
||||
'''
|
||||
获取支付信息
|
||||
:param xml_data:
|
||||
:return:
|
||||
'''
|
||||
|
||||
sign = self.create_sign( pay_data )
|
||||
pay_data ['sign'] = sign
|
||||
xml_data = self.dict_to_xml( pay_data )
|
||||
headers = {'Content-Type': 'application/xml'}
|
||||
url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
|
||||
r = requests.post( url= url, data=xml_data.encode('utf-8'),headers = headers)
|
||||
r.encoding = "utf-8"
|
||||
app.logger.info( r.text )
|
||||
if r.status_code == 200:
|
||||
prepay_id = self.xml_to_dict( r.text ).get('prepay_id')
|
||||
pay_sign_data = {
|
||||
'appId': pay_data.get('appid'),
|
||||
'timeStamp': pay_data.get('out_trade_no'),
|
||||
'nonceStr': pay_data.get('nonce_str'),
|
||||
'package': 'prepay_id={0}'.format(prepay_id),
|
||||
'signType': 'MD5'
|
||||
}
|
||||
pay_sign = self.create_sign( pay_sign_data )
|
||||
pay_sign_data.pop('appId')
|
||||
pay_sign_data['paySign'] = pay_sign
|
||||
pay_sign_data['prepay_id'] = prepay_id
|
||||
return pay_sign_data
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def dict_to_xml(self,dict_data):
|
||||
'''
|
||||
dict to xml
|
||||
:param dict_data:
|
||||
:return:
|
||||
'''
|
||||
xml = ["<xml>"]
|
||||
for k, v in dict_data.items():
|
||||
xml.append("<{0}>{1}</{0}>".format(k, v))
|
||||
xml.append("</xml>")
|
||||
return "".join(xml)
|
||||
|
||||
def xml_to_dict(self,xml_data):
|
||||
'''
|
||||
xml to dict
|
||||
:param xml_data:
|
||||
:return:
|
||||
'''
|
||||
xml_dict = {}
|
||||
root = ET.fromstring(xml_data)
|
||||
for child in root:
|
||||
xml_dict[child.tag] = child.text
|
||||
return xml_dict
|
||||
|
||||
def get_nonce_str(self):
|
||||
'''
|
||||
获取随机字符串
|
||||
:return:
|
||||
'''
|
||||
return str(uuid.uuid4()).replace('-', '')
|
||||
|
||||
def getAccessToken(self):
|
||||
token = None
|
||||
token_info = OauthAccessToken.query.filter( OauthAccessToken.expired_time >= getCurrentDate() ).first()
|
||||
if token_info:
|
||||
token = token_info.access_token
|
||||
return token
|
||||
|
||||
config_mina = app.config['MINA_APP']
|
||||
url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"\
|
||||
.format( config_mina['appid'],config_mina['appkey'] )
|
||||
|
||||
r = requests.get( url = url )
|
||||
if r.status_code != 200 or not r.text:
|
||||
return token
|
||||
|
||||
data = json.loads( r.text )
|
||||
now = datetime.datetime.now()
|
||||
date = now + datetime.timedelta(seconds=data['expires_in'] - 200)
|
||||
model_token = OauthAccessToken()
|
||||
model_token.access_token = data['access_token']
|
||||
model_token.expired_time = date.strftime( "%Y-%m-%d %H:%M:%S" )
|
||||
model_token.created_time = getCurrentDate()
|
||||
db.session.add( model_token )
|
||||
db.session.commit()
|
||||
|
||||
return data['access_token']
|
||||
|
||||
|
||||
21
common/libs/queue/QueueService.py
Normal file
21
common/libs/queue/QueueService.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
from common.models.queue.QueueList import QueueList
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from application import app,db
|
||||
class QueueService():
|
||||
|
||||
@staticmethod
|
||||
def addQueue( queue_name,data = None ):
|
||||
model_queue = QueueList()
|
||||
model_queue.queue_name = queue_name
|
||||
if data:
|
||||
model_queue.data = json.dumps( data )
|
||||
|
||||
model_queue.created_time = model_queue.updated_time = getCurrentDate()
|
||||
db.session.add( model_queue )
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
13
common/models/food/WxShareHistory.py
Normal file
13
common/models/food/WxShareHistory.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Integer, String
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class WxShareHistory(db.Model):
|
||||
__tablename__ = 'wx_share_history'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
member_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
share_url = db.Column(db.String(200), nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
26
common/models/member/MemberAddress.py
Normal file
26
common/models/member/MemberAddress.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Index, Integer, String
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
class MemberAddress(db.Model):
|
||||
__tablename__ = 'member_address'
|
||||
__table_args__ = (
|
||||
db.Index('idx_member_id_status', 'member_id', 'status'),
|
||||
)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
member_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
nickname = db.Column(db.String(20), nullable=False, server_default=db.FetchedValue())
|
||||
mobile = db.Column(db.String(11), nullable=False, server_default=db.FetchedValue())
|
||||
province_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
province_str = db.Column(db.String(50), nullable=False, server_default=db.FetchedValue())
|
||||
city_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
city_str = db.Column(db.String(50), nullable=False, server_default=db.FetchedValue())
|
||||
area_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
area_str = db.Column(db.String(50), nullable=False, server_default=db.FetchedValue())
|
||||
address = db.Column(db.String(100), nullable=False, server_default=db.FetchedValue())
|
||||
status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
is_default = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
15
common/models/member/MemberCart.py
Normal file
15
common/models/member/MemberCart.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import BigInteger, Column, DateTime, Integer
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class MemberCart(db.Model):
|
||||
__tablename__ = 'member_cart'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
member_id = db.Column(db.BigInteger, nullable=False, index=True, server_default=db.FetchedValue())
|
||||
food_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
quantity = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
25
common/models/member/MemberComments.py
Normal file
25
common/models/member/MemberComments.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Integer, String
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class MemberComments(db.Model):
|
||||
__tablename__ = 'member_comments'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
member_id = db.Column(db.Integer, nullable=False, index=True, server_default=db.FetchedValue())
|
||||
food_ids = db.Column(db.String(200), nullable=False, server_default=db.FetchedValue())
|
||||
pay_order_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
score = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
content = db.Column(db.String(200), nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
|
||||
@property
|
||||
def score_desc(self):
|
||||
score_map = {
|
||||
"10": "好评",
|
||||
"6": "中评",
|
||||
"0": "差评",
|
||||
}
|
||||
return score_map[ str( self.score ) ]
|
||||
21
common/models/member/OauthMemberBind.py
Normal file
21
common/models/member/OauthMemberBind.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Index, Integer, String, Text
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class OauthMemberBind(db.Model):
|
||||
__tablename__ = 'oauth_member_bind'
|
||||
__table_args__ = (
|
||||
db.Index('idx_type_openid', 'type', 'openid'),
|
||||
)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
member_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
client_type = db.Column(db.String(20), nullable=False, server_default=db.FetchedValue())
|
||||
type = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
openid = db.Column(db.String(80), nullable=False, server_default=db.FetchedValue())
|
||||
unionid = db.Column(db.String(100), nullable=False, server_default=db.FetchedValue())
|
||||
extra = db.Column(db.Text, nullable=False)
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
13
common/models/pay/OauthAccessToken.py
Normal file
13
common/models/pay/OauthAccessToken.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Integer, String
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class OauthAccessToken(db.Model):
|
||||
__tablename__ = 'oauth_access_token'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
access_token = db.Column(db.String(600), nullable=False, server_default=db.FetchedValue())
|
||||
expired_time = db.Column(db.DateTime, nullable=False, index=True, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
51
common/models/pay/PayOrder.py
Normal file
51
common/models/pay/PayOrder.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import BigInteger, Column, DateTime, Index, Integer, Numeric, String, Text
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db,app
|
||||
|
||||
|
||||
class PayOrder(db.Model):
|
||||
__tablename__ = 'pay_order'
|
||||
__table_args__ = (
|
||||
db.Index('idx_member_id_status', 'member_id', 'status'),
|
||||
)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
order_sn = db.Column(db.String(40), nullable=False, unique=True, server_default=db.FetchedValue())
|
||||
member_id = db.Column(db.BigInteger, nullable=False, server_default=db.FetchedValue())
|
||||
total_price = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
yun_price = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
pay_price = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
pay_sn = db.Column(db.String(128), nullable=False, server_default=db.FetchedValue())
|
||||
prepay_id = db.Column(db.String(128), nullable=False, server_default=db.FetchedValue())
|
||||
note = db.Column(db.Text, nullable=False)
|
||||
status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
express_status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
express_address_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
express_info = db.Column(db.String(100), nullable=False, server_default=db.FetchedValue())
|
||||
comment_status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
pay_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
|
||||
|
||||
@property
|
||||
def pay_status(self):
|
||||
tmp_status = self.status
|
||||
if self.status == 1:
|
||||
tmp_status = self.express_status
|
||||
if self.express_status == 1 and self.comment_status == 0:
|
||||
tmp_status = -5
|
||||
if self.express_status == 1 and self.comment_status == 1:
|
||||
tmp_status = 1
|
||||
return tmp_status
|
||||
|
||||
@property
|
||||
def status_desc(self):
|
||||
return app.config['PAY_STATUS_DISPLAY_MAPPING'][ str( self.pay_status )]
|
||||
|
||||
@property
|
||||
def order_number(self):
|
||||
order_number = self.created_time.strftime("%Y%m%d%H%M%S")
|
||||
order_number = order_number + str(self.id).zfill(5)
|
||||
return order_number
|
||||
15
common/models/pay/PayOrderCallbackData.py
Normal file
15
common/models/pay/PayOrderCallbackData.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Integer, Text
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class PayOrderCallbackData(db.Model):
|
||||
__tablename__ = 'pay_order_callback_data'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
pay_order_id = db.Column(db.Integer, nullable=False, unique=True, server_default=db.FetchedValue())
|
||||
pay_data = db.Column(db.Text, nullable=False)
|
||||
refund_data = db.Column(db.Text, nullable=False)
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
19
common/models/pay/PayOrderItem.py
Normal file
19
common/models/pay/PayOrderItem.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import BigInteger, Column, DateTime, Integer, Numeric, Text
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class PayOrderItem(db.Model):
|
||||
__tablename__ = 'pay_order_item'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
pay_order_id = db.Column(db.Integer, nullable=False, index=True, server_default=db.FetchedValue())
|
||||
member_id = db.Column(db.BigInteger, nullable=False, server_default=db.FetchedValue())
|
||||
quantity = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
price = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
food_id = db.Column(db.Integer, nullable=False, index=True, server_default=db.FetchedValue())
|
||||
note = db.Column(db.Text, nullable=False)
|
||||
status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
15
common/models/queue/QueueList.py
Normal file
15
common/models/queue/QueueList.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, DateTime, Integer, String
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class QueueList(db.Model):
|
||||
__tablename__ = 'queue_list'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
queue_name = db.Column(db.String(30), nullable=False, server_default=db.FetchedValue())
|
||||
data = db.Column(db.String(500), nullable=False, server_default=db.FetchedValue())
|
||||
status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
19
common/models/stat/StatDailyFood.py
Normal file
19
common/models/stat/StatDailyFood.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, Date, DateTime, Index, Integer, Numeric
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class StatDailyFood(db.Model):
|
||||
__tablename__ = 'stat_daily_food'
|
||||
__table_args__ = (
|
||||
db.Index('date_food_id', 'date', 'food_id'),
|
||||
)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
date = db.Column(db.Date, nullable=False)
|
||||
food_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
total_count = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
total_pay_money = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
19
common/models/stat/StatDailyMember.py
Normal file
19
common/models/stat/StatDailyMember.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, Date, DateTime, Index, Integer, Numeric
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class StatDailyMember(db.Model):
|
||||
__tablename__ = 'stat_daily_member'
|
||||
__table_args__ = (
|
||||
db.Index('idx_date_member_id', 'date', 'member_id'),
|
||||
)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
date = db.Column(db.Date, nullable=False)
|
||||
member_id = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
total_shared_count = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
|
||||
total_pay_money = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
18
common/models/stat/StatDailySite.py
Normal file
18
common/models/stat/StatDailySite.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# coding: utf-8
|
||||
from sqlalchemy import Column, Date, DateTime, Integer, Numeric
|
||||
from sqlalchemy.schema import FetchedValue
|
||||
from application import db
|
||||
|
||||
|
||||
class StatDailySite(db.Model):
|
||||
__tablename__ = 'stat_daily_site'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
date = db.Column(db.Date, nullable=False, index=True)
|
||||
total_pay_money = db.Column(db.Numeric(10, 2), nullable=False, server_default=db.FetchedValue())
|
||||
total_member_count = db.Column(db.Integer, nullable=False)
|
||||
total_new_member_count = db.Column(db.Integer, nullable=False)
|
||||
total_order_count = db.Column(db.Integer, nullable=False)
|
||||
total_shared_count = db.Column(db.Integer, nullable=False)
|
||||
updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue())
|
||||
@@ -7,8 +7,7 @@ AUTH_COOKIE_NAME = "mooc_food"
|
||||
|
||||
##过滤url
|
||||
IGNORE_URLS = [
|
||||
"^/user/login",
|
||||
"^/api"
|
||||
"^/user/login"
|
||||
]
|
||||
|
||||
IGNORE_CHECK_LOGIN_URLS = [
|
||||
@@ -16,7 +15,9 @@ IGNORE_CHECK_LOGIN_URLS = [
|
||||
"^/favicon.ico"
|
||||
]
|
||||
|
||||
|
||||
API_IGNORE_URLS = [
|
||||
"^/api"
|
||||
]
|
||||
|
||||
PAGE_SIZE = 50
|
||||
PAGE_DISPLAY = 10
|
||||
@@ -29,7 +30,7 @@ STATUS_MAPPING = {
|
||||
|
||||
MINA_APP = {
|
||||
'appid':'wx2c65877d37fc29bf',
|
||||
'appkey':'8c61791794cde415042924a9714542a9',
|
||||
'appkey':'b670fb4798ec6abf4bab32ae3cf14a61',
|
||||
'paykey':'xxxxxxxxxxxxxx换自己的',
|
||||
'mch_id':'xxxxxxxxxxxx换自己的',
|
||||
'callback_url':'/api/order/callback'
|
||||
@@ -43,4 +44,20 @@ UPLOAD = {
|
||||
|
||||
APP = {
|
||||
'domain':'http://127.0.0.1:9000'
|
||||
}
|
||||
|
||||
|
||||
PAY_STATUS_MAPPING = {
|
||||
"1":"已支付",
|
||||
"-8":"待支付",
|
||||
"0":"已关闭"
|
||||
}
|
||||
|
||||
PAY_STATUS_DISPLAY_MAPPING = {
|
||||
"0":"订单关闭",
|
||||
"1":"支付成功",
|
||||
"-8":"待支付",
|
||||
"-7":"待发货",
|
||||
"-6":"待确认",
|
||||
"-5":"待评价"
|
||||
}
|
||||
3
jobs/bash_jobs
Normal file
3
jobs/bash_jobs
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
export ops_config=production
|
||||
. /data/www/python3_vir/bin/activate
|
||||
57
jobs/launcher.py
Normal file
57
jobs/launcher.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from application import app,manager
|
||||
from flask_script import Command,Option
|
||||
import argparse,sys,traceback
|
||||
|
||||
'''
|
||||
python manage.py runjob -m Test ( jobs/tasks/Test.py )
|
||||
python manage.py runjob -m test/Index ( jobs/tasks/test/Index.py )
|
||||
* name or flags - 名称或选项字符串列表, e.g. foo or -f, --foo.
|
||||
* action - 参数如果定义了选项,表示这是一个操作参数,至于调用时做哪种操作由用户输入或者default决定。
|
||||
* nargs - 应该使用的命令行参数数。.
|
||||
* const - 某些动作或参数个数的常数值。.
|
||||
* default - 如果命令行没有对输入这个参数相应的值,则此参数用default给出的值.
|
||||
* type -将用户输入的值转化为哪种类型.
|
||||
* choices - 参数可输入值的范围或选择.
|
||||
* required - 命令行输入的值是否可以被忽略(布尔量).
|
||||
* help - 参数的简要描述.
|
||||
* metavar - useage中显示的参数的名称.
|
||||
* dest - 要添加到解析参数返回的对象中的属性的名称.
|
||||
'''
|
||||
class runJob( Command ):
|
||||
|
||||
capture_all_args = True
|
||||
def run(self,*args,**kwargs):
|
||||
args = sys.argv[2:]
|
||||
parser = argparse.ArgumentParser( add_help = True )
|
||||
|
||||
parser.add_argument("-m","--name",dest = "name",metavar = "name", help="指定job名",required=True)
|
||||
parser.add_argument("-a","--act",dest = "act",metavar = "act", help="Job动作",required=False)
|
||||
parser.add_argument("-p","--param",dest = "param",nargs = "*", metavar = "param",help="业务参数",default = '',required=False)
|
||||
params = parser.parse_args( args )
|
||||
params_dict = params.__dict__
|
||||
ret_params = {}
|
||||
for item in params_dict.keys():
|
||||
ret_params[ item ] = params_dict[ item ]
|
||||
|
||||
if "name" not in ret_params or not ret_params['name']:
|
||||
return self.tips()
|
||||
|
||||
module_name = ret_params['name'].replace( "/","." )
|
||||
try:
|
||||
import_string = "from jobs.tasks.%s import JobTask as job_target" % ( module_name )
|
||||
exec( import_string , globals() )
|
||||
target = job_target()
|
||||
target.run( ret_params )
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def tips(self):
|
||||
tip_msg = '''
|
||||
请正确调度Job
|
||||
python manage runjob -m Test ( jobs/tasks/Test.py )
|
||||
python manage runjob -m test/Index ( jobs/tasks/test/Index.py )
|
||||
'''
|
||||
app.logger.info( tip_msg )
|
||||
return False
|
||||
9
jobs/readme.md
Normal file
9
jobs/readme.md
Normal file
@@ -0,0 +1,9 @@
|
||||
Job 列表
|
||||
======
|
||||
* 队列Job
|
||||
|
||||
* * * * * { . ~/.bash_jobs && cd /data/www/Order && python manager.py runjob -m queue/index ;} >> /data/www/logs/queue_list.`date +\%Y_\%m_\%d`.log 2>&1
|
||||
* * * * * { . ~/.bash_jobs && cd /data/www/Order && python manager.py runjob -m pay/index ;} >> /data/www/logs/pay_index.`date +\%Y_\%m_\%d`.log 2>&1
|
||||
1 2 * * { . ~/.bash_jobs && cd /data/www/Order && python manager.py runjob -m stat/daily -a member ;} >> /data/www/logs/pay_index.`date +\%Y_\%m_\%d`.log 2>&1
|
||||
2 2 * * * { . ~/.bash_jobs && cd /data/www/Order && python manager.py runjob -m stat/daily -a food ;} >> /data/www/logs/pay_index.`date +\%Y_\%m_\%d`.log 2>&1
|
||||
3 2 * * * { . ~/.bash_jobs && cd /data/www/Order && python manager.py runjob -m stat/daily -a site ;} >> /data/www/logs/pay_index.`date +\%Y_\%m_\%d`.log 2>&1
|
||||
26
jobs/tasks/pay/index.py
Normal file
26
jobs/tasks/pay/index.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.libs.Helper import getFormatDate
|
||||
from common.libs.pay.PayService import PayService
|
||||
import datetime
|
||||
from application import app,db
|
||||
'''
|
||||
python manager.py runjob -m pay/index
|
||||
'''
|
||||
|
||||
class JobTask():
|
||||
def __init__(self):
|
||||
pass
|
||||
def run(self,params):
|
||||
now = datetime.datetime.now()
|
||||
date_before_30min = now + datetime.timedelta( minutes = -30 )
|
||||
list = PayOrder.query.filter_by( status = -8 ).\
|
||||
filter( PayOrder.created_time <= getFormatDate( date = date_before_30min ) ).all()
|
||||
if not list:
|
||||
app.logger.info("no data~~")
|
||||
return
|
||||
|
||||
pay_target = PayService()
|
||||
for item in list:
|
||||
pay_target.closeOrder( pay_order_id = item.id )
|
||||
app.logger.info("it's over~~")
|
||||
110
jobs/tasks/queue/index.py
Normal file
110
jobs/tasks/queue/index.py
Normal file
@@ -0,0 +1,110 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from application import app,db
|
||||
from common.models.queue.QueueList import QueueList
|
||||
import json,requests,datetime
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from common.libs.pay.WeChatService import WeChatService
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.models.pay.PayOrderItem import PayOrderItem
|
||||
from common.models.member.OauthMemberBind import OauthMemberBind
|
||||
from common.models.food.Food import Food
|
||||
from common.models.food.FoodSaleChangeLog import FoodSaleChangeLog
|
||||
from sqlalchemy import func
|
||||
|
||||
'''
|
||||
python manager.py runjob -m queue/index
|
||||
'''
|
||||
|
||||
class JobTask():
|
||||
def __init__(self):
|
||||
pass
|
||||
def run(self,params):
|
||||
list = QueueList.query.filter_by(status = -1 )\
|
||||
.order_by( QueueList.id.asc() ).limit(1).all()
|
||||
for item in list:
|
||||
if item.queue_name == "pay":
|
||||
self.handlePay( item )
|
||||
|
||||
item.status = 1
|
||||
item.updated_time = getCurrentDate()
|
||||
db.session.add( item )
|
||||
db.session.commit()
|
||||
|
||||
def handlePay(self,item ):
|
||||
data = json.loads( item.data )
|
||||
if 'member_id' not in data or 'pay_order_id' not in data:
|
||||
return False
|
||||
|
||||
oauth_bind_info = OauthMemberBind.query.filter_by(member_id=data['member_id']).first()
|
||||
if not oauth_bind_info:
|
||||
return False
|
||||
|
||||
pay_order_info = PayOrder.query.filter_by( id = data['pay_order_id']).first()
|
||||
if not pay_order_info:
|
||||
return False
|
||||
|
||||
#更新销售总量
|
||||
pay_order_items = PayOrderItem.query.filter_by( pay_order_id = pay_order_info.id ).all()
|
||||
notice_content = []
|
||||
if pay_order_items:
|
||||
date_from = datetime.datetime.now().strftime( "%Y-%m-01 00:00:00" )
|
||||
date_to = datetime.datetime.now().strftime( "%Y-%m-31 23:59:59" )
|
||||
for item in pay_order_items:
|
||||
tmp_food_info = Food.query.filter_by( id = item.food_id ).first()
|
||||
if not tmp_food_info:
|
||||
continue
|
||||
|
||||
notice_content.append( "%s %s份"%( tmp_food_info.name,item.quantity) )
|
||||
|
||||
#当月数量
|
||||
tmp_stat_info = db.session.query(FoodSaleChangeLog, func.sum(FoodSaleChangeLog.quantity).label("total")) \
|
||||
.filter( FoodSaleChangeLog.food_id == item.food_id )\
|
||||
.filter( FoodSaleChangeLog.created_time >= date_from,FoodSaleChangeLog.created_time <= date_to ).first()
|
||||
tmp_month_count = tmp_stat_info[ 1 ] if tmp_stat_info[ 1 ] else 0
|
||||
tmp_food_info.total_count += 1
|
||||
tmp_food_info.month_count = tmp_month_count
|
||||
db.session.add( tmp_food_info )
|
||||
db.session.commit()
|
||||
|
||||
keyword1_val = pay_order_info.note if pay_order_info.note else '无'
|
||||
keyword2_val = "、".join( notice_content )
|
||||
keyword3_val = str( pay_order_info.total_price )
|
||||
keyword4_val = str( pay_order_info.order_number )
|
||||
keyword5_val = ""
|
||||
if pay_order_info.express_info:
|
||||
express_info = json.loads( pay_order_info.express_info )
|
||||
keyword5_val = str( express_info['address'] )
|
||||
#发送模板消息
|
||||
target_wechat = WeChatService( )
|
||||
access_token = target_wechat.getAccessToken()
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=%s"%access_token
|
||||
params = {
|
||||
"touser": oauth_bind_info.openid,
|
||||
"template_id":"8aqlWFAjZZ_NnR0_vOvHGcwHglvIlAYRaUyOmFD5kvs",
|
||||
"page": "pages/my/order_list",
|
||||
"form_id": pay_order_info.prepay_id,
|
||||
"data": {
|
||||
"keyword1": {
|
||||
"value": keyword1_val
|
||||
},
|
||||
"keyword2": {
|
||||
"value": keyword2_val
|
||||
},
|
||||
"keyword3": {
|
||||
"value": keyword3_val
|
||||
},
|
||||
"keyword4": {
|
||||
"value": keyword4_val
|
||||
},
|
||||
"keyword5": {
|
||||
"value": keyword5_val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = requests.post(url=url, data= json.dumps( params ).encode('utf-8'), headers=headers)
|
||||
r.encoding = "utf-8"
|
||||
app.logger.info(r.text)
|
||||
return True
|
||||
|
||||
215
jobs/tasks/stat/daily.py
Normal file
215
jobs/tasks/stat/daily.py
Normal file
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from application import app,db
|
||||
from common.libs.Helper import getFormatDate,getCurrentDate
|
||||
from common.models.member.Member import Member
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.models.stat.StatDailyFood import StatDailyFood
|
||||
from common.models.stat.StatDailySite import StatDailySite
|
||||
from common.models.stat.StatDailyMember import StatDailyMember
|
||||
from common.models.food.WxShareHistory import WxShareHistory
|
||||
from common.models.food.FoodSaleChangeLog import FoodSaleChangeLog
|
||||
from sqlalchemy import func
|
||||
import random
|
||||
'''
|
||||
python manager.py runjob -m stat/daily -a member|food|site -p 2018-07-01
|
||||
'''
|
||||
class JobTask():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def run(self, params):
|
||||
act = params['act'] if 'act' in params else ''
|
||||
date = params['param'][0] if params['param'] and len(params['param']) else getFormatDate(format="%Y-%m-%d")
|
||||
if not act:
|
||||
return
|
||||
|
||||
date_from = date + " 00:00:00"
|
||||
date_to = date + " 23:59:59"
|
||||
func_params = {
|
||||
'act': act,
|
||||
'date':date,
|
||||
'date_from':date_from,
|
||||
'date_to':date_to
|
||||
}
|
||||
if act == "member":
|
||||
self.statMember( func_params )
|
||||
elif act == "food":
|
||||
self.statFood( func_params )
|
||||
elif act == "site":
|
||||
self.statSite( func_params)
|
||||
elif act == "test":
|
||||
self.test()
|
||||
|
||||
app.logger.info("it's over~~")
|
||||
return
|
||||
|
||||
'''
|
||||
会员统计
|
||||
'''
|
||||
def statMember(self,params):
|
||||
act = params['act']
|
||||
date = params['date']
|
||||
date_from = params['date_from']
|
||||
date_to = params['date_to']
|
||||
app.logger.info( "act:{0},from:{1},to:{2}".format( act,date_from,date_to ) )
|
||||
|
||||
member_list = Member.query.all()
|
||||
if not member_list:
|
||||
app.logger.info( "no member list" )
|
||||
return
|
||||
|
||||
for member_info in member_list:
|
||||
tmp_stat_member = StatDailyMember.query.filter_by( date = date,member_id = member_info.id ).first()
|
||||
if tmp_stat_member:
|
||||
tmp_model_stat_member = tmp_stat_member
|
||||
else:
|
||||
tmp_model_stat_member = StatDailyMember()
|
||||
tmp_model_stat_member.date = date
|
||||
tmp_model_stat_member.member_id = member_info.id
|
||||
tmp_model_stat_member.created_time = getCurrentDate()
|
||||
|
||||
tmp_stat_pay = db.session.query( func.sum(PayOrder.total_price).label("total_pay_money")) \
|
||||
.filter( PayOrder.member_id == member_info.id ,PayOrder.status == 1 )\
|
||||
.filter( PayOrder.created_time >= date_from,PayOrder.created_time <= date_to ).first()
|
||||
tmp_stat_share_count = WxShareHistory.query.filter( PayOrder.member_id == member_info.id )\
|
||||
.filter( PayOrder.created_time >= date_from,PayOrder.created_time <= date_to ).count()
|
||||
|
||||
tmp_model_stat_member.total_shared_count = tmp_stat_share_count
|
||||
tmp_model_stat_member.total_pay_money = tmp_stat_pay[ 0 ] if tmp_stat_pay[ 0 ] else 0.00
|
||||
'''
|
||||
为了测试效果模拟数据
|
||||
'''
|
||||
tmp_model_stat_member.total_shared_count = random.randint(50,100)
|
||||
tmp_model_stat_member.total_pay_money = random.randint(1000,1010)
|
||||
tmp_model_stat_member.updated_time = getCurrentDate()
|
||||
db.session.add( tmp_model_stat_member )
|
||||
db.session.commit()
|
||||
|
||||
return
|
||||
|
||||
'''
|
||||
Food统计
|
||||
'''
|
||||
def statFood(self,params):
|
||||
act = params['act']
|
||||
date = params['date']
|
||||
date_from = params['date_from']
|
||||
date_to = params['date_to']
|
||||
app.logger.info( "act:{0},from:{1},to:{2}".format( act,date_from,date_to ) )
|
||||
|
||||
stat_food_list = db.session.query(FoodSaleChangeLog.food_id, func.sum(FoodSaleChangeLog.quantity).label("total_count"),
|
||||
func.sum(FoodSaleChangeLog.price).label("total_pay_money")) \
|
||||
.filter(FoodSaleChangeLog.created_time >= date_from, FoodSaleChangeLog.created_time <= date_to)\
|
||||
.group_by( FoodSaleChangeLog.food_id ).all()
|
||||
|
||||
if not stat_food_list:
|
||||
app.logger.info("no data")
|
||||
return
|
||||
|
||||
for item in stat_food_list:
|
||||
tmp_food_id = item[ 0 ]
|
||||
tmp_stat_food = StatDailyFood.query.filter_by(date=date, food_id = tmp_food_id ).first()
|
||||
if tmp_stat_food:
|
||||
tmp_model_stat_food = tmp_stat_food
|
||||
else:
|
||||
tmp_model_stat_food = StatDailyFood()
|
||||
tmp_model_stat_food.date = date
|
||||
tmp_model_stat_food.food_id = tmp_food_id
|
||||
tmp_model_stat_food.created_time = getCurrentDate()
|
||||
|
||||
tmp_model_stat_food.total_count = item[1]
|
||||
tmp_model_stat_food.total_pay_money = item[2]
|
||||
tmp_model_stat_food.updated_time = getCurrentDate()
|
||||
|
||||
'''
|
||||
为了测试效果模拟数据
|
||||
'''
|
||||
tmp_model_stat_food.total_count = random.randint(50, 100)
|
||||
tmp_model_stat_food.total_pay_money = random.randint(1000, 1010)
|
||||
|
||||
db.session.add( tmp_model_stat_food )
|
||||
db.session.commit()
|
||||
|
||||
return
|
||||
'''
|
||||
site统计
|
||||
'''
|
||||
def statSite(self,params):
|
||||
act = params['act']
|
||||
date = params['date']
|
||||
date_from = params['date_from']
|
||||
date_to = params['date_to']
|
||||
app.logger.info( "act:{0},from:{1},to:{2}".format( act,date_from,date_to ) )
|
||||
|
||||
stat_pay = db.session.query(func.sum(PayOrder.total_price).label("total_pay_money")) \
|
||||
.filter(PayOrder.status == 1) \
|
||||
.filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to).first()
|
||||
|
||||
stat_member_count = Member.query.count()
|
||||
stat_new_member_count = Member.query.filter(Member.created_time >= date_from,
|
||||
Member.created_time <= date_to).count()
|
||||
|
||||
stat_order_count = PayOrder.query.filter_by( status = 1 )\
|
||||
.filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to)\
|
||||
.count()
|
||||
|
||||
stat_share_count = WxShareHistory.query.filter(WxShareHistory.created_time >= date_from
|
||||
, WxShareHistory.created_time <= date_to).count()
|
||||
|
||||
tmp_stat_site = StatDailySite.query.filter_by(date=date).first()
|
||||
if tmp_stat_site:
|
||||
tmp_model_stat_site = tmp_stat_site
|
||||
else:
|
||||
tmp_model_stat_site = StatDailySite()
|
||||
tmp_model_stat_site.date = date
|
||||
tmp_model_stat_site.created_time = getCurrentDate()
|
||||
|
||||
tmp_model_stat_site.total_pay_money = stat_pay[ 0 ] if stat_pay[ 0 ] else 0.00
|
||||
tmp_model_stat_site.total_new_member_count = stat_new_member_count
|
||||
tmp_model_stat_site.total_member_count = stat_member_count
|
||||
tmp_model_stat_site.total_order_count = stat_order_count
|
||||
tmp_model_stat_site.total_shared_count = stat_share_count
|
||||
tmp_model_stat_site.updated_time = getCurrentDate()
|
||||
'''
|
||||
为了测试效果模拟数据
|
||||
'''
|
||||
tmp_model_stat_site.total_pay_money = random.randint(1000, 1010)
|
||||
tmp_model_stat_site.total_new_member_count = random.randint(50, 100)
|
||||
tmp_model_stat_site.total_member_count += tmp_model_stat_site.total_new_member_count
|
||||
tmp_model_stat_site.total_order_count = random.randint(900, 1000)
|
||||
tmp_model_stat_site.total_shared_count = random.randint(1000, 2000)
|
||||
db.session.add(tmp_model_stat_site)
|
||||
db.session.commit()
|
||||
|
||||
def test(self):
|
||||
import datetime
|
||||
from common.libs.Helper import getFormatDate
|
||||
now = datetime.datetime.now()
|
||||
for i in reversed( range( 1,30 ) ):
|
||||
date_before = now + datetime.timedelta( days = -i )
|
||||
date = getFormatDate( date = date_before,format = "%Y-%m-%d" )
|
||||
tmp_params = {
|
||||
'act': 'test',
|
||||
'date': date,
|
||||
'date_from': date + " 00:00:00",
|
||||
'date_to': date + " 23:59:59"
|
||||
}
|
||||
self.testFood( date )
|
||||
self.statFood( tmp_params )
|
||||
self.statMember( tmp_params )
|
||||
self.statSite( tmp_params )
|
||||
|
||||
def testFood(self,date):
|
||||
from common.models.food.Food import Food
|
||||
list = Food.query.all()
|
||||
if list:
|
||||
for item in list:
|
||||
model = FoodSaleChangeLog()
|
||||
model.food_id = item.id
|
||||
model.quantity = random.randint( 1,10 )
|
||||
model.price = model.quantity * item.price
|
||||
model.member_id = 1
|
||||
model.created_time = date + " " + getFormatDate( format = "%H:%M:%S")
|
||||
db.session.add( model )
|
||||
db.session.commit()
|
||||
@@ -2,10 +2,14 @@
|
||||
from application import app,manager
|
||||
from flask_script import Server
|
||||
import www
|
||||
from jobs.launcher import runJob
|
||||
|
||||
##web server
|
||||
manager.add_command( "runserver", Server( host='0.0.0.0',port=app.config['SERVER_PORT'],use_debugger = True ,use_reloader = True) )
|
||||
|
||||
#job entrance
|
||||
manager.add_command('runjob', runJob() )
|
||||
|
||||
def main():
|
||||
manager.run( )
|
||||
|
||||
|
||||
2
mina
2
mina
Submodule mina updated: fb3fd6da10...2205b70d34
172
web/controllers/api/Address.py
Normal file
172
web/controllers/api/Address.py
Normal file
@@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request, jsonify,g
|
||||
from application import app,db
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from common.models.member.MemberAddress import MemberAddress
|
||||
|
||||
|
||||
@route_api.route("/my/address/index")
|
||||
def myAddressList():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
list = MemberAddress.query.filter_by( status = 1, member_id = member_info.id )\
|
||||
.order_by( MemberAddress.id.desc() ).all()
|
||||
data_list = []
|
||||
if list:
|
||||
for item in list:
|
||||
tmp_data = {
|
||||
"id":item.id,
|
||||
"nickname":item.nickname,
|
||||
"mobile":item.mobile,
|
||||
"is_default":item.is_default,
|
||||
"address":"%s%s%s%s"%( item.province_str,item.city_str,item.area_str,item.address ),
|
||||
}
|
||||
data_list.append( tmp_data )
|
||||
resp['data']['list'] = data_list
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/my/address/set",methods = [ "POST" ])
|
||||
def myAddressSet():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = int( req['id'] ) if 'id' in req and req['id'] else 0
|
||||
nickname = req['nickname'] if 'nickname' in req else ''
|
||||
address = req['address'] if 'address' in req else ''
|
||||
mobile = req['mobile'] if 'mobile' in req else ''
|
||||
|
||||
province_id = int( req['province_id'] ) if ( 'province_id' in req and req['province_id'] ) else 0
|
||||
province_str = req['province_str'] if 'province_str' in req else ''
|
||||
city_id = int( req['city_id'] ) if ( 'city_id' in req and req['city_id'])else 0
|
||||
city_str = req['city_str'] if 'city_str' in req else ''
|
||||
district_id = int( req['district_id'] ) if ( 'district_id' in req and req['district_id'] ) else 0
|
||||
district_str = req['district_str'] if 'district_str' in req else ''
|
||||
|
||||
member_info = g.member_info
|
||||
|
||||
if not nickname:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请填写联系人姓名~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if not mobile:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请填写手机号码~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if province_id < 1:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请选择地区~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if city_id < 1:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请选择地区~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if district_id < 1:
|
||||
district_str = ''
|
||||
|
||||
if not address:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请填写详细地址~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
address_info = MemberAddress.query.filter_by( id = id,member_id = member_info.id ).first()
|
||||
if address_info:
|
||||
model_address = address_info
|
||||
else:
|
||||
default_address_count = MemberAddress.query.filter_by( is_default = 1,member_id = member_info.id ,status = 1).count()
|
||||
model_address = MemberAddress()
|
||||
model_address.member_id = member_info.id
|
||||
model_address.is_default = 1 if default_address_count == 0 else 0
|
||||
model_address.created_time = getCurrentDate()
|
||||
|
||||
model_address.nickname = nickname
|
||||
model_address.mobile = mobile
|
||||
model_address.address = address
|
||||
model_address.province_id = province_id
|
||||
model_address.province_str = province_str
|
||||
model_address.city_id = city_id
|
||||
model_address.city_str = city_str
|
||||
model_address.area_id = district_id
|
||||
model_address.area_str = district_str
|
||||
model_address.updated_time = getCurrentDate()
|
||||
db.session.add(model_address )
|
||||
db.session.commit()
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/my/address/info")
|
||||
def myAddressInfo():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = int( req['id'] ) if 'id' in req else 0
|
||||
member_info = g.member_info
|
||||
|
||||
if id < 1 or not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
address_info = MemberAddress.query.filter_by( id = id ).first()
|
||||
if not address_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
resp['data']['info'] = {
|
||||
"nickname":address_info.nickname,
|
||||
"mobile":address_info.mobile,
|
||||
"address":address_info.address,
|
||||
"province_id":address_info.province_id,
|
||||
"province_str":address_info.province_str,
|
||||
"city_id":address_info.city_id,
|
||||
"city_str":address_info.city_str,
|
||||
"area_id":address_info.area_id,
|
||||
"area_str":address_info.area_str
|
||||
}
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
@route_api.route("/my/address/ops",methods = [ "POST" ])
|
||||
def myAddressOps():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = int(req['id']) if 'id' in req else 0
|
||||
act = req['act'] if 'act' in req else ''
|
||||
member_info = g.member_info
|
||||
|
||||
if id < 1 or not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
address_info = MemberAddress.query.filter_by(id=id,member_id = member_info.id).first()
|
||||
if not address_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if act == "del":
|
||||
address_info.status = 0
|
||||
address_info.updated_time = getCurrentDate()
|
||||
db.session.add(address_info)
|
||||
db.session.commit()
|
||||
elif act == "default":
|
||||
MemberAddress.query.filter_by( member_id=member_info.id)\
|
||||
.update({ 'is_default' :0 })
|
||||
address_info.is_default = 1
|
||||
address_info.updated_time = getCurrentDate()
|
||||
db.session.add(address_info)
|
||||
db.session.commit()
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
|
||||
|
||||
99
web/controllers/api/Cart.py
Normal file
99
web/controllers/api/Cart.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request,jsonify,g
|
||||
from common.models.food.Food import Food
|
||||
from common.models.member.MemberCart import MemberCart
|
||||
from common.libs.member.CartService import CartService
|
||||
from common.libs.Helper import selectFilterObj,getDictFilterField
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from application import app,db
|
||||
import json
|
||||
|
||||
@route_api.route("/cart/index")
|
||||
def cartIndex():
|
||||
resp = {'code': 200, 'msg': '添加购物车成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
if not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "获取失败,伪登录~~"
|
||||
return jsonify(resp)
|
||||
cart_list = MemberCart.query.filter_by( member_id=member_info.id).all()
|
||||
data_cart_list = []
|
||||
if cart_list:
|
||||
food_ids = selectFilterObj( cart_list,"food_id" )
|
||||
food_map = getDictFilterField( Food,Food.id,"id",food_ids )
|
||||
for item in cart_list:
|
||||
tmp_food_info = food_map[ item.food_id ]
|
||||
tmp_data = {
|
||||
"id":item.id,
|
||||
"number":item.quantity,
|
||||
"food_id": item.food_id,
|
||||
"name":tmp_food_info.name,
|
||||
"price":str( tmp_food_info.price ),
|
||||
"pic_url": UrlManager.buildImageUrl( tmp_food_info.main_image ),
|
||||
"active":True
|
||||
}
|
||||
data_cart_list.append( tmp_data )
|
||||
|
||||
resp['data']['list'] = data_cart_list
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/cart/set", methods=["POST"])
|
||||
def setCart():
|
||||
resp = {'code': 200, 'msg': '添加购物车成功~', 'data': {}}
|
||||
req = request.values
|
||||
food_id = int(req['id']) if 'id' in req else 0
|
||||
number = int(req['number']) if 'number' in req else 0
|
||||
if food_id < 1 or number < 1:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "添加购物车失败-1~~"
|
||||
return jsonify(resp)
|
||||
|
||||
member_info = g.member_info
|
||||
if not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "添加购物车失败-2~~"
|
||||
return jsonify(resp)
|
||||
|
||||
food_info = Food.query.filter_by( id = food_id ).first()
|
||||
if not food_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "添加购物车失败-3~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if food_info.stock < number:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "添加购物车失败,库存不足~~"
|
||||
return jsonify(resp)
|
||||
|
||||
ret = CartService.setItems( member_id=member_info.id,food_id = food_info.id,number = number )
|
||||
if not ret:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "添加购物车失败-4~~"
|
||||
return jsonify(resp)
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/cart/del", methods=["POST"])
|
||||
def delCart():
|
||||
resp = {'code': 200, 'msg': '添加购物车成功~', 'data': {}}
|
||||
req = request.values
|
||||
params_goods = req['goods'] if 'goods' in req else None
|
||||
|
||||
items = []
|
||||
if params_goods:
|
||||
items = json.loads(params_goods)
|
||||
if not items or len( items ) < 1:
|
||||
return jsonify(resp)
|
||||
|
||||
member_info = g.member_info
|
||||
if not member_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "删除购物车失败-1~~"
|
||||
return jsonify(resp)
|
||||
|
||||
ret = CartService.deleteItem( member_id = member_info.id, items = items )
|
||||
if not ret:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "删除购物车失败-2~~"
|
||||
return jsonify(resp)
|
||||
return jsonify(resp)
|
||||
142
web/controllers/api/Food.py
Normal file
142
web/controllers/api/Food.py
Normal file
@@ -0,0 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request,jsonify,g
|
||||
from common.models.food.FoodCat import FoodCat
|
||||
from common.models.food.Food import Food
|
||||
from common.models.member.MemberCart import MemberCart
|
||||
from common.models.member.MemberComments import MemberComments
|
||||
from common.models.member.Member import Member
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.Helper import getCurrentDate,getDictFilterField,selectFilterObj
|
||||
from application import app,db
|
||||
from sqlalchemy import or_
|
||||
|
||||
@route_api.route("/food/index" )
|
||||
def foodIndex():
|
||||
resp = { 'code':200 ,'msg':'操作成功~','data':{} }
|
||||
cat_list = FoodCat.query.filter_by( status = 1 ).order_by( FoodCat.weight.desc() ).all()
|
||||
data_cat_list = []
|
||||
data_cat_list.append({
|
||||
'id': 0,
|
||||
'name': "全部"
|
||||
})
|
||||
if cat_list:
|
||||
for item in cat_list:
|
||||
tmp_data = {
|
||||
'id':item.id,
|
||||
'name':item.name
|
||||
}
|
||||
data_cat_list.append( tmp_data )
|
||||
resp['data']['cat_list'] = data_cat_list
|
||||
|
||||
food_list = Food.query.filter_by( status = 1 )\
|
||||
.order_by( Food.total_count.desc(),Food.id.desc() ).limit(3).all()
|
||||
|
||||
data_food_list = []
|
||||
if food_list:
|
||||
for item in food_list:
|
||||
tmp_data = {
|
||||
'id':item.id,
|
||||
'pic_url':UrlManager.buildImageUrl( item.main_image )
|
||||
}
|
||||
data_food_list.append( tmp_data )
|
||||
|
||||
resp['data']['banner_list'] = data_food_list
|
||||
return jsonify( resp )
|
||||
|
||||
@route_api.route("/food/search" )
|
||||
def foodSearch():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
cat_id = int( req['cat_id'] ) if 'cat_id' in req else 0
|
||||
mix_kw = str(req['mix_kw']) if 'mix_kw' in req else ''
|
||||
p = int( req['p'] ) if 'p' in req else 1
|
||||
|
||||
if p < 1:
|
||||
p = 1
|
||||
|
||||
page_size = 10
|
||||
offset = ( p - 1 ) * page_size
|
||||
query = Food.query.filter_by(status=1 )
|
||||
if cat_id > 0:
|
||||
query = query.filter_by(cat_id = cat_id)
|
||||
|
||||
if mix_kw:
|
||||
rule = or_(Food.name.ilike("%{0}%".format(mix_kw)), Food.tags.ilike("%{0}%".format(mix_kw)))
|
||||
query = query.filter(rule)
|
||||
|
||||
food_list = query.order_by(Food.total_count.desc(), Food.id.desc())\
|
||||
.offset( offset ).limit( page_size ).all()
|
||||
|
||||
data_food_list = []
|
||||
if food_list:
|
||||
for item in food_list:
|
||||
tmp_data = {
|
||||
'id': item.id,
|
||||
'name': "%s"%( item.name ),
|
||||
'price': str( item.price ),
|
||||
'min_price':str( item.price ),
|
||||
'pic_url': UrlManager.buildImageUrl(item.main_image)
|
||||
}
|
||||
data_food_list.append(tmp_data)
|
||||
resp['data']['list'] = data_food_list
|
||||
resp['data']['has_more'] = 0 if len( data_food_list ) < page_size else 1
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/food/info" )
|
||||
def foodInfo():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = int(req['id']) if 'id' in req else 0
|
||||
food_info = Food.query.filter_by( id = id ).first()
|
||||
if not food_info or not food_info.status :
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "美食已下架"
|
||||
return jsonify(resp)
|
||||
|
||||
member_info = g.member_info
|
||||
cart_number = 0
|
||||
if member_info:
|
||||
cart_number = MemberCart.query.filter_by( member_id = member_info.id ).count()
|
||||
resp['data']['info'] = {
|
||||
"id":food_info.id,
|
||||
"name":food_info.name,
|
||||
"summary":food_info.summary,
|
||||
"total_count":food_info.total_count,
|
||||
"comment_count":food_info.comment_count,
|
||||
'main_image':UrlManager.buildImageUrl( food_info.main_image ),
|
||||
"price":str( food_info.price ),
|
||||
"stock":food_info.stock,
|
||||
"pics":[ UrlManager.buildImageUrl( food_info.main_image ) ]
|
||||
}
|
||||
resp['data']['cart_number'] = cart_number
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
@route_api.route("/food/comments")
|
||||
def foodComments():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = int(req['id']) if 'id' in req else 0
|
||||
query = MemberComments.query.filter( MemberComments.food_ids.ilike("%_{0}_%".format(id)) )
|
||||
list = query.order_by( MemberComments.id.desc() ).limit(5).all()
|
||||
data_list = []
|
||||
if list:
|
||||
member_map = getDictFilterField( Member,Member.id,"id",selectFilterObj( list,"member_id" ) )
|
||||
for item in list:
|
||||
if item.member_id not in member_map:
|
||||
continue
|
||||
tmp_member_info = member_map[ item.member_id ]
|
||||
tmp_data = {
|
||||
'score':item.score_desc,
|
||||
'date': item.created_time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"content":item.content,
|
||||
"user":{
|
||||
'nickname':tmp_member_info.nickname,
|
||||
'avatar_url':tmp_member_info.avatar,
|
||||
}
|
||||
}
|
||||
data_list.append( tmp_data )
|
||||
resp['data']['list'] = data_list
|
||||
resp['data']['count'] = query.count()
|
||||
return jsonify(resp)
|
||||
@@ -1,36 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request,jsonify
|
||||
from application import app,db
|
||||
from flask import request,jsonify,g
|
||||
from application import app,db
|
||||
import requests,json
|
||||
from common.models.member.Member import Member
|
||||
from common.models.member.Oauth_member_bind import OauthMemberBind
|
||||
from common.models.member.OauthMemberBind import OauthMemberBind
|
||||
from common.models.food.WxShareHistory import WxShareHistory
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from common.libs.member.MemberService import MemberService
|
||||
|
||||
@route_api.route("/member/login",methods = [ "GET","POST" ])
|
||||
def login():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
resp = { 'code':200 ,'msg':'操作成功~','data':{} }
|
||||
req = request.values
|
||||
code = req['code'] if 'code' in req else ''
|
||||
app.logger.info(code)
|
||||
if not code or len(code) < 1:
|
||||
if not code or len( code ) < 1:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "需要code"
|
||||
return jsonify(resp)
|
||||
|
||||
openid = MemberService.getWeChatOpenId(code)
|
||||
|
||||
openid = MemberService.getWeChatOpenId( code )
|
||||
if openid is None:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "调用微信出错"
|
||||
return jsonify(resp)
|
||||
|
||||
nickname = req['nickName'] if 'nickName' in req else ''
|
||||
sex = req['gender'] if 'gender' in req else 0
|
||||
avatar = req['avatarUrl'] if 'avatarUrl' in req else ''
|
||||
'''
|
||||
判断是否已经测试过,注册了直接返回一些信息
|
||||
'''
|
||||
bind_info = OauthMemberBind.query.filter_by(openid=openid, type=1).first()
|
||||
bind_info = OauthMemberBind.query.filter_by( openid = openid,type = 1 ).first()
|
||||
if not bind_info:
|
||||
model_member = Member()
|
||||
model_member.nickname = nickname
|
||||
@@ -51,10 +53,11 @@ def login():
|
||||
db.session.commit()
|
||||
|
||||
bind_info = model_bind
|
||||
member_info = Member.query.filter_by(id=bind_info.member_id).first()
|
||||
|
||||
member_info = Member.query.filter_by(id = bind_info.member_id).first()
|
||||
token = "%s#%s" % (MemberService.geneAuthCode(member_info), member_info.id)
|
||||
resp['data'] = {'token': token}
|
||||
return jsonify(resp)
|
||||
return jsonify( resp )
|
||||
|
||||
|
||||
@route_api.route("/member/check-reg",methods = [ "GET","POST" ])
|
||||
@@ -87,4 +90,30 @@ def checkReg():
|
||||
|
||||
token = "%s#%s"%( MemberService.geneAuthCode( member_info ),member_info.id )
|
||||
resp['data'] = { 'token':token }
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/member/share",methods = [ "POST" ])
|
||||
def memberShare():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
url = req['url'] if 'url' in req else ''
|
||||
member_info = g.member_info
|
||||
model_share = WxShareHistory()
|
||||
if member_info:
|
||||
model_share.member_id = member_info.id
|
||||
model_share.share_url = url
|
||||
model_share.created_time = getCurrentDate()
|
||||
db.session.add(model_share)
|
||||
db.session.commit()
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
@route_api.route("/member/info")
|
||||
def memberInfo():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
resp['data']['info'] = {
|
||||
"nickname":member_info.nickname,
|
||||
"avatar_url":member_info.avatar
|
||||
}
|
||||
return jsonify(resp)
|
||||
179
web/controllers/api/My.py
Normal file
179
web/controllers/api/My.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request, jsonify,g
|
||||
from common.models.food.Food import Food
|
||||
from application import app,db
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.models.pay.PayOrderItem import PayOrderItem
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.Helper import selectFilterObj,getDictFilterField,getCurrentDate
|
||||
from common.models.member.MemberComments import MemberComments
|
||||
import json,datetime
|
||||
|
||||
@route_api.route("/my/order")
|
||||
def myOrderList():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
req = request.values
|
||||
status = int( req['status'] ) if 'status' in req else 0
|
||||
query = PayOrder.query.filter_by( member_id = member_info.id )
|
||||
if status == -8 :#等待付款
|
||||
query = query.filter( PayOrder.status == -8 )
|
||||
elif status == -7:#待发货
|
||||
query = query.filter( PayOrder.status == 1,PayOrder.express_status == -7,PayOrder.comment_status == 0 )
|
||||
elif status == -6:#待确认
|
||||
query = query.filter(PayOrder.status == 1, PayOrder.express_status == -6,PayOrder.comment_status == 0)
|
||||
elif status == -5:#待评价
|
||||
query = query.filter(PayOrder.status == 1, PayOrder.express_status == 1,PayOrder.comment_status == 0)
|
||||
elif status == 1:#已完成
|
||||
query = query.filter(PayOrder.status == 1, PayOrder.express_status == 1,PayOrder.comment_status == 1 )
|
||||
else:
|
||||
query = query.filter( PayOrder.status == 0 )
|
||||
|
||||
pay_order_list = query.order_by( PayOrder.id.desc() ).all()
|
||||
data_pay_order_list = []
|
||||
if pay_order_list:
|
||||
pay_order_ids = selectFilterObj( pay_order_list,"id" )
|
||||
pay_order_item_list = PayOrderItem.query.filter( PayOrderItem.pay_order_id.in_( pay_order_ids ) ).all()
|
||||
food_ids = selectFilterObj( pay_order_item_list,"food_id" )
|
||||
food_map = getDictFilterField( Food,Food.id,"id",food_ids )
|
||||
pay_order_item_map = {}
|
||||
if pay_order_item_list:
|
||||
for item in pay_order_item_list:
|
||||
if item.pay_order_id not in pay_order_item_map:
|
||||
pay_order_item_map[ item.pay_order_id ] = []
|
||||
|
||||
tmp_food_info = food_map[ item.food_id ]
|
||||
pay_order_item_map[item.pay_order_id].append({
|
||||
'id':item.id,
|
||||
'food_id':item.food_id,
|
||||
'quantity':item.quantity,
|
||||
'price':str( item.price ),
|
||||
'pic_url':UrlManager.buildImageUrl( tmp_food_info.main_image ),
|
||||
'name':tmp_food_info.name
|
||||
})
|
||||
|
||||
|
||||
for item in pay_order_list:
|
||||
tmp_data = {
|
||||
'status':item.pay_status,
|
||||
'status_desc':item.status_desc,
|
||||
'date':item.created_time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
'order_number':item.order_number,
|
||||
'order_sn':item.order_sn,
|
||||
'note':item.note,
|
||||
'total_price':str( item.total_price ),
|
||||
'goods_list':pay_order_item_map[ item.id ]
|
||||
}
|
||||
|
||||
data_pay_order_list.append( tmp_data )
|
||||
resp['data']['pay_order_list'] = data_pay_order_list
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/my/order/info")
|
||||
def myOrderInfo():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
req = request.values
|
||||
order_sn = req['order_sn'] if 'order_sn' in req else ''
|
||||
pay_order_info = PayOrder.query.filter_by( member_id=member_info.id ,order_sn = order_sn).first()
|
||||
if not pay_order_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
express_info = {}
|
||||
if pay_order_info.express_info:
|
||||
express_info = json.loads( pay_order_info.express_info )
|
||||
|
||||
tmp_deadline = pay_order_info.created_time + datetime.timedelta(minutes=30)
|
||||
info = {
|
||||
"order_sn":pay_order_info.order_sn,
|
||||
"status":pay_order_info.pay_status,
|
||||
"status_desc":pay_order_info.status_desc,
|
||||
"pay_price":str( pay_order_info.pay_price),
|
||||
"yun_price":str( pay_order_info.yun_price),
|
||||
"total_price":str( pay_order_info.total_price),
|
||||
"address":express_info,
|
||||
"goods": [],
|
||||
"deadline":tmp_deadline.strftime("%Y-%m-%d %H:%M")
|
||||
}
|
||||
|
||||
pay_order_items = PayOrderItem.query.filter_by( pay_order_id = pay_order_info.id ).all()
|
||||
if pay_order_items:
|
||||
food_ids = selectFilterObj( pay_order_items , "food_id")
|
||||
food_map = getDictFilterField(Food, Food.id, "id", food_ids)
|
||||
for item in pay_order_items:
|
||||
tmp_food_info = food_map[item.food_id]
|
||||
tmp_data = {
|
||||
"name": tmp_food_info.name,
|
||||
"price": str( item.price ),
|
||||
"unit": item.quantity,
|
||||
"pic_url": UrlManager.buildImageUrl( tmp_food_info.main_image ),
|
||||
}
|
||||
info['goods'].append( tmp_data )
|
||||
resp['data']['info'] = info
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
@route_api.route("/my/comment/add",methods = [ "POST" ])
|
||||
def myCommentAdd():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
req = request.values
|
||||
order_sn = req['order_sn'] if 'order_sn' in req else ''
|
||||
score = req['score'] if 'score' in req else 10
|
||||
content = req['content'] if 'content' in req else ''
|
||||
|
||||
pay_order_info = PayOrder.query.filter_by( member_id=member_info.id ,order_sn = order_sn).first()
|
||||
if not pay_order_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙,请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if pay_order_info.comment_status:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "已经评价过了~~"
|
||||
return jsonify(resp)
|
||||
|
||||
pay_order_items = PayOrderItem.query.filter_by( pay_order_id = pay_order_info.id ).all()
|
||||
food_ids = selectFilterObj( pay_order_items,"food_id" )
|
||||
tmp_food_ids_str = '_'.join(str(s) for s in food_ids if s not in [None])
|
||||
model_comment = MemberComments()
|
||||
model_comment.food_ids = "_%s_"%tmp_food_ids_str
|
||||
model_comment.member_id = member_info.id
|
||||
model_comment.pay_order_id = pay_order_info.id
|
||||
model_comment.score = score
|
||||
model_comment.content = content
|
||||
db.session.add( model_comment )
|
||||
|
||||
pay_order_info.comment_status = 1
|
||||
pay_order_info.updated_time = getCurrentDate()
|
||||
db.session.add( pay_order_info )
|
||||
|
||||
db.session.commit()
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/my/comment/list" )
|
||||
def myCommentList():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
comment_list = MemberComments.query.filter_by( member_id=member_info.id )\
|
||||
.order_by(MemberComments.id.desc()).all()
|
||||
data_comment_list = []
|
||||
if comment_list:
|
||||
pay_order_ids = selectFilterObj( comment_list,"pay_order_id" )
|
||||
pay_order_map = getDictFilterField( PayOrder,PayOrder.id,"id",pay_order_ids )
|
||||
for item in comment_list:
|
||||
tmp_pay_order_info = pay_order_map[ item.pay_order_id ]
|
||||
tmp_data = {
|
||||
"date":item.created_time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"content":item.content,
|
||||
"order_number":tmp_pay_order_info.order_number
|
||||
}
|
||||
data_comment_list.append( tmp_data )
|
||||
resp['data']['list'] = data_comment_list
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
|
||||
223
web/controllers/api/Order.py
Normal file
223
web/controllers/api/Order.py
Normal file
@@ -0,0 +1,223 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from web.controllers.api import route_api
|
||||
from flask import request, jsonify,g
|
||||
from application import app, db
|
||||
import json, decimal
|
||||
from common.models.food.Food import Food
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.Helper import getCurrentDate
|
||||
from common.libs.pay.PayService import PayService
|
||||
from common.libs.pay.WeChatService import WeChatService
|
||||
from common.libs.member.CartService import CartService
|
||||
from common.models.member.MemberAddress import MemberAddress
|
||||
from common.models.member.OauthMemberBind import OauthMemberBind
|
||||
|
||||
|
||||
@route_api.route("/order/info", methods=[ "POST" ])
|
||||
def orderInfo():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
params_goods = req['goods'] if 'goods' in req else None
|
||||
member_info = g.member_info
|
||||
params_goods_list = []
|
||||
if params_goods:
|
||||
params_goods_list = json.loads(params_goods)
|
||||
|
||||
food_dic = {}
|
||||
for item in params_goods_list:
|
||||
food_dic[item['id']] = item['number']
|
||||
|
||||
food_ids = food_dic.keys()
|
||||
food_list = Food.query.filter(Food.id.in_(food_ids)).all()
|
||||
data_food_list = []
|
||||
yun_price = pay_price = decimal.Decimal(0.00)
|
||||
if food_list:
|
||||
for item in food_list:
|
||||
tmp_data = {
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"price": str(item.price),
|
||||
'pic_url': UrlManager.buildImageUrl(item.main_image),
|
||||
'number': food_dic[item.id]
|
||||
}
|
||||
pay_price = pay_price + item.price * int( food_dic[item.id] )
|
||||
data_food_list.append(tmp_data)
|
||||
|
||||
# 获取地址
|
||||
address_info = MemberAddress.query.filter_by( is_default = 1,member_id = member_info.id,status = 1 ).first()
|
||||
default_address = ''
|
||||
if address_info:
|
||||
default_address = {
|
||||
"id": address_info.id,
|
||||
"name": address_info.nickname,
|
||||
"mobile": address_info.mobile,
|
||||
"address":"%s%s%s%s"%( address_info.province_str,address_info.city_str,address_info.area_str,address_info.address )
|
||||
}
|
||||
|
||||
resp['data']['food_list'] = data_food_list
|
||||
resp['data']['pay_price'] = str(pay_price)
|
||||
resp['data']['yun_price'] = str(yun_price)
|
||||
resp['data']['total_price'] = str(pay_price + yun_price)
|
||||
resp['data']['default_address'] = default_address
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/order/create", methods=[ "POST"])
|
||||
def orderCreate():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
type = req['type'] if 'type' in req else ''
|
||||
note = req['note'] if 'note' in req else ''
|
||||
express_address_id = int( req['express_address_id'] ) if 'express_address_id' in req and req['express_address_id'] else 0
|
||||
params_goods = req['goods'] if 'goods' in req else None
|
||||
|
||||
items = []
|
||||
if params_goods:
|
||||
items = json.loads(params_goods)
|
||||
|
||||
if len( items ) < 1:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "下单失败:没有选择商品~~"
|
||||
return jsonify(resp)
|
||||
|
||||
address_info = MemberAddress.query.filter_by( id = express_address_id ).first()
|
||||
if not address_info or not address_info.status:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "下单失败:快递地址不对~~"
|
||||
return jsonify(resp)
|
||||
|
||||
member_info = g.member_info
|
||||
target = PayService()
|
||||
params = {
|
||||
"note":note,
|
||||
'express_address_id':address_info.id,
|
||||
'express_info':{
|
||||
'mobile':address_info.mobile,
|
||||
'nickname':address_info.nickname,
|
||||
"address":"%s%s%s%s"%( address_info.province_str,address_info.city_str,address_info.area_str,address_info.address )
|
||||
}
|
||||
}
|
||||
resp = target.createOrder( member_info.id ,items ,params)
|
||||
#如果是来源购物车的,下单成功将下单的商品去掉
|
||||
if resp['code'] == 200 and type == "cart":
|
||||
CartService.deleteItem( member_info.id,items )
|
||||
|
||||
return jsonify( resp )
|
||||
|
||||
@route_api.route("/order/pay", methods=[ "POST"])
|
||||
def orderPay():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
member_info = g.member_info
|
||||
req = request.values
|
||||
order_sn = req['order_sn'] if 'order_sn' in req else ''
|
||||
pay_order_info = PayOrder.query.filter_by( order_sn = order_sn,member_id = member_info.id ).first()
|
||||
if not pay_order_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙。请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
oauth_bind_info = OauthMemberBind.query.filter_by( member_id = member_info.id ).first()
|
||||
if not oauth_bind_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙。请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
config_mina = app.config['MINA_APP']
|
||||
notify_url = app.config['APP']['domain'] + config_mina['callback_url']
|
||||
|
||||
target_wechat = WeChatService( merchant_key=config_mina['paykey'] )
|
||||
|
||||
data = {
|
||||
'appid': config_mina['appid'],
|
||||
'mch_id': config_mina['mch_id'],
|
||||
'nonce_str': target_wechat.get_nonce_str(),
|
||||
'body': '订餐', # 商品描述
|
||||
'out_trade_no': pay_order_info.order_sn, # 商户订单号
|
||||
'total_fee': int( pay_order_info.total_price * 100 ),
|
||||
'notify_url': notify_url,
|
||||
'trade_type': "JSAPI",
|
||||
'openid': oauth_bind_info.openid
|
||||
}
|
||||
|
||||
pay_info = target_wechat.get_pay_info( pay_data=data)
|
||||
|
||||
#保存prepay_id为了后面发模板消息
|
||||
pay_order_info.prepay_id = pay_info['prepay_id']
|
||||
db.session.add( pay_order_info )
|
||||
db.session.commit()
|
||||
|
||||
resp['data']['pay_info'] = pay_info
|
||||
return jsonify(resp)
|
||||
|
||||
@route_api.route("/order/callback", methods=[ "POST"])
|
||||
def orderCallback():
|
||||
result_data = {
|
||||
'return_code': 'SUCCESS',
|
||||
'return_msg': 'OK'
|
||||
}
|
||||
header = {'Content-Type': 'application/xml'}
|
||||
config_mina = app.config['MINA_APP']
|
||||
target_wechat = WeChatService(merchant_key=config_mina['paykey'])
|
||||
callback_data = target_wechat.xml_to_dict( request.data )
|
||||
app.logger.info( callback_data )
|
||||
sign = callback_data['sign']
|
||||
callback_data.pop( 'sign' )
|
||||
gene_sign = target_wechat.create_sign( callback_data )
|
||||
app.logger.info(gene_sign)
|
||||
if sign != gene_sign:
|
||||
result_data['return_code'] = result_data['return_msg'] = 'FAIL'
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
if callback_data['result_code'] != 'SUCCESS':
|
||||
result_data['return_code'] = result_data['return_msg'] = 'FAIL'
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
|
||||
order_sn = callback_data['out_trade_no']
|
||||
pay_order_info = PayOrder.query.filter_by(order_sn=order_sn).first()
|
||||
if not pay_order_info:
|
||||
result_data['return_code'] = result_data['return_msg'] = 'FAIL'
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
|
||||
if int( pay_order_info.total_price * 100 ) != int( callback_data['total_fee'] ):
|
||||
result_data['return_code'] = result_data['return_msg'] = 'FAIL'
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
|
||||
if pay_order_info.status == 1:
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
|
||||
target_pay = PayService()
|
||||
target_pay.orderSuccess( pay_order_id = pay_order_info.id,params = { "pay_sn":callback_data['transaction_id'] } )
|
||||
target_pay.addPayCallbackData( pay_order_id = pay_order_info.id, data = request.data)
|
||||
return target_wechat.dict_to_xml(result_data), header
|
||||
|
||||
@route_api.route("/order/ops", methods=[ "POST"])
|
||||
def orderOps():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
member_info = g.member_info
|
||||
order_sn = req['order_sn'] if 'order_sn' in req else ''
|
||||
act = req['act'] if 'act' in req else ''
|
||||
pay_order_info = PayOrder.query.filter_by(order_sn=order_sn, member_id=member_info.id).first()
|
||||
if not pay_order_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙。请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
if act == "cancel":
|
||||
target_pay = PayService( )
|
||||
ret = target_pay.closeOrder( pay_order_id=pay_order_info.id )
|
||||
if not ret:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙。请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
elif act == "confirm":
|
||||
pay_order_info.express_status = 1
|
||||
pay_order_info.updated_time = getCurrentDate()
|
||||
db.session.add( pay_order_info )
|
||||
db.session.commit()
|
||||
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from flask import Blueprint
|
||||
route_api = Blueprint('api_page',__name__ )
|
||||
route_api = Blueprint( 'api_page',__name__ )
|
||||
from web.controllers.api.Member import *
|
||||
from web.controllers.api.Food import *
|
||||
from web.controllers.api.Order import *
|
||||
from web.controllers.api.My import *
|
||||
from web.controllers.api.Cart import *
|
||||
from web.controllers.api.Address import *
|
||||
|
||||
@route_api.route("/")
|
||||
def index():
|
||||
|
||||
103
web/controllers/chart.py
Normal file
103
web/controllers/chart.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from application import app,db
|
||||
from flask import Blueprint,jsonify
|
||||
from common.libs.Helper import ops_render
|
||||
from common.libs.Helper import getFormatDate
|
||||
from common.models.stat.StatDailySite import StatDailySite
|
||||
import datetime
|
||||
route_chart = Blueprint( 'chart_page',__name__ )
|
||||
|
||||
@route_chart.route("/dashboard")
|
||||
def dashboard():
|
||||
now = datetime.datetime.now()
|
||||
date_before_30days = now + datetime.timedelta(days=-30)
|
||||
date_from = getFormatDate(date=date_before_30days, format="%Y-%m-%d")
|
||||
date_to = getFormatDate(date=now, format="%Y-%m-%d")
|
||||
|
||||
list = StatDailySite.query.filter(StatDailySite.date >= date_from) \
|
||||
.filter(StatDailySite.date <= date_to).order_by(StatDailySite.id.asc()) \
|
||||
.all()
|
||||
|
||||
resp = {'code': 200, 'msg': '操作成功~~', 'data': {}}
|
||||
data = {
|
||||
"categories":[],
|
||||
"series":[
|
||||
{
|
||||
"name":"会员总数",
|
||||
"data":[]
|
||||
},
|
||||
{
|
||||
"name": "订单总数",
|
||||
"data": []
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if list:
|
||||
for item in list:
|
||||
data['categories'].append( getFormatDate( date = item.date ,format = "%Y-%m-%d") )
|
||||
data['series'][0]['data'].append( item.total_member_count )
|
||||
data['series'][1]['data'].append( item.total_order_count )
|
||||
|
||||
resp['data'] = data
|
||||
return jsonify(resp)
|
||||
|
||||
@route_chart.route("/finance")
|
||||
def finance():
|
||||
now = datetime.datetime.now()
|
||||
date_before_30days = now + datetime.timedelta(days=-30)
|
||||
date_from = getFormatDate(date=date_before_30days, format="%Y-%m-%d")
|
||||
date_to = getFormatDate(date=now, format="%Y-%m-%d")
|
||||
|
||||
list = StatDailySite.query.filter(StatDailySite.date >= date_from) \
|
||||
.filter(StatDailySite.date <= date_to).order_by(StatDailySite.id.asc()) \
|
||||
.all()
|
||||
|
||||
resp = {'code': 200, 'msg': '操作成功~~', 'data': {}}
|
||||
data = {
|
||||
"categories":[],
|
||||
"series":[
|
||||
{
|
||||
"name":"日营收报表",
|
||||
"data":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if list:
|
||||
for item in list:
|
||||
data['categories'].append( getFormatDate( date = item.date ,format = "%Y-%m-%d") )
|
||||
data['series'][0]['data'].append( float( item.total_pay_money ) )
|
||||
|
||||
resp['data'] = data
|
||||
return jsonify(resp)
|
||||
|
||||
@route_chart.route("/share")
|
||||
def share():
|
||||
now = datetime.datetime.now()
|
||||
date_before_30days = now + datetime.timedelta(days=-30)
|
||||
date_from = getFormatDate(date=date_before_30days, format="%Y-%m-%d")
|
||||
date_to = getFormatDate(date=now, format="%Y-%m-%d")
|
||||
|
||||
list = StatDailySite.query.filter(StatDailySite.date >= date_from) \
|
||||
.filter(StatDailySite.date <= date_to).order_by(StatDailySite.id.asc()) \
|
||||
.all()
|
||||
|
||||
resp = {'code': 200, 'msg': '操作成功~~', 'data': {}}
|
||||
data = {
|
||||
"categories":[],
|
||||
"series":[
|
||||
{
|
||||
"name":"日分享",
|
||||
"data":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if list:
|
||||
for item in list:
|
||||
data['categories'].append( getFormatDate( date = item.date ,format = "%Y-%m-%d") )
|
||||
data['series'][0]['data'].append( item.total_shared_count )
|
||||
|
||||
resp['data'] = data
|
||||
return jsonify(resp)
|
||||
@@ -1,17 +1,174 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from flask import Blueprint
|
||||
from flask import Blueprint,request,redirect,jsonify
|
||||
from common.libs.Helper import ops_render
|
||||
|
||||
from common.models.member.Member import Member
|
||||
from common.models.food.Food import Food
|
||||
from common.models.pay.PayOrder import PayOrder
|
||||
from common.models.pay.PayOrderItem import PayOrderItem
|
||||
from application import app,db
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.Helper import iPagination,selectFilterObj,getDictListFilterField,getDictFilterField,getCurrentDate
|
||||
from sqlalchemy import func
|
||||
import json
|
||||
route_finance = Blueprint( 'finance_page',__name__ )
|
||||
|
||||
@route_finance.route( "/index" )
|
||||
def index():
|
||||
return ops_render( "finance/index.html" )
|
||||
resp_data = {}
|
||||
req = request.values
|
||||
page = int(req['p']) if ('p' in req and req['p']) else 1
|
||||
|
||||
query = PayOrder.query
|
||||
|
||||
if 'status' in req and int( req['status'] ) > -1 :
|
||||
query = query.filter( PayOrder.status == int( req['status'] ) )
|
||||
|
||||
page_params = {
|
||||
'total': query.count(),
|
||||
'page_size': app.config['PAGE_SIZE'],
|
||||
'page': page,
|
||||
'display': app.config['PAGE_DISPLAY'],
|
||||
'url': request.full_path.replace("&p={}".format(page), "")
|
||||
}
|
||||
|
||||
pages = iPagination(page_params)
|
||||
offset = (page - 1) * app.config['PAGE_SIZE']
|
||||
pay_list = query.order_by(PayOrder.id.desc()).offset(offset).limit(app.config['PAGE_SIZE']).all()
|
||||
data_list = []
|
||||
if pay_list:
|
||||
pay_order_ids = selectFilterObj( pay_list,"id" )
|
||||
pay_order_items_map = getDictListFilterField( PayOrderItem,PayOrderItem.pay_order_id,"pay_order_id", pay_order_ids )
|
||||
|
||||
food_mapping = {}
|
||||
if pay_order_items_map:
|
||||
food_ids = []
|
||||
for item in pay_order_items_map:
|
||||
tmp_food_ids = selectFilterObj( pay_order_items_map[ item ],"food_id" )
|
||||
tmp_food_ids = {}.fromkeys(tmp_food_ids).keys()
|
||||
food_ids = food_ids + list( tmp_food_ids )
|
||||
|
||||
#food_ids里面会有重复的,要去重
|
||||
food_mapping = getDictFilterField( Food,Food.id,"id", food_ids )
|
||||
|
||||
for item in pay_list:
|
||||
tmp_data = {
|
||||
"id":item.id,
|
||||
"status_desc":item.status_desc,
|
||||
"order_number":item.order_number,
|
||||
"price":item.total_price,
|
||||
"pay_time":item.pay_time,
|
||||
"created_time":item.created_time.strftime("%Y%m%d%H%M%S")
|
||||
}
|
||||
tmp_foods = []
|
||||
tmp_order_items = pay_order_items_map[ item.id ]
|
||||
for tmp_order_item in tmp_order_items:
|
||||
tmp_food_info = food_mapping[ tmp_order_item.food_id ]
|
||||
tmp_foods.append( {
|
||||
'name':tmp_food_info.name,
|
||||
'quantity':tmp_order_item.quantity
|
||||
} )
|
||||
|
||||
tmp_data['foods'] = tmp_foods
|
||||
data_list.append( tmp_data )
|
||||
|
||||
resp_data['list'] = data_list
|
||||
resp_data['pages'] = pages
|
||||
resp_data['search_con'] = req
|
||||
resp_data['pay_status_mapping'] = app.config['PAY_STATUS_MAPPING']
|
||||
resp_data['current'] = 'index'
|
||||
|
||||
return ops_render( "finance/index.html",resp_data )
|
||||
|
||||
@route_finance.route( "/pay-info" )
|
||||
def payInfo():
|
||||
return ops_render( "finance/pay_info.html" )
|
||||
def info():
|
||||
resp_data = {}
|
||||
req = request.values
|
||||
id = int(req['id']) if 'id' in req else 0
|
||||
|
||||
reback_url = UrlManager.buildUrl("/finance/index")
|
||||
|
||||
if id < 1:
|
||||
return redirect( reback_url )
|
||||
|
||||
pay_order_info = PayOrder.query.filter_by( id = id ).first()
|
||||
if not pay_order_info:
|
||||
return redirect(reback_url)
|
||||
|
||||
member_info = Member.query.filter_by( id = pay_order_info.member_id ).first()
|
||||
if not member_info:
|
||||
return redirect(reback_url)
|
||||
|
||||
order_item_list = PayOrderItem.query.filter_by( pay_order_id = pay_order_info.id ).all()
|
||||
data_order_item_list = []
|
||||
if order_item_list:
|
||||
food_map = getDictFilterField(Food, Food.id, "id", selectFilterObj(order_item_list, "food_id"))
|
||||
for item in order_item_list:
|
||||
tmp_food_info = food_map[ item.food_id ]
|
||||
tmp_data = {
|
||||
"quantity":item.quantity,
|
||||
"price":item.price,
|
||||
"name":tmp_food_info.name
|
||||
}
|
||||
data_order_item_list.append( tmp_data )
|
||||
|
||||
address_info = {}
|
||||
if pay_order_info.express_info:
|
||||
address_info = json.loads(pay_order_info.express_info)
|
||||
|
||||
resp_data['pay_order_info'] = pay_order_info
|
||||
resp_data['pay_order_items'] = data_order_item_list
|
||||
resp_data['member_info'] = member_info
|
||||
resp_data['address_info'] = address_info
|
||||
resp_data['current'] = 'index'
|
||||
return ops_render( "finance/pay_info.html",resp_data )
|
||||
|
||||
@route_finance.route( "/account" )
|
||||
def account():
|
||||
return ops_render( "finance/account.html" )
|
||||
def set():
|
||||
resp_data = {}
|
||||
req = request.values
|
||||
page = int(req['p']) if ('p' in req and req['p']) else 1
|
||||
query = PayOrder.query.filter_by( status = 1 )
|
||||
|
||||
page_params = {
|
||||
'total': query.count(),
|
||||
'page_size': app.config['PAGE_SIZE'],
|
||||
'page': page,
|
||||
'display': app.config['PAGE_DISPLAY'],
|
||||
'url': request.full_path.replace("&p={}".format(page), "")
|
||||
}
|
||||
|
||||
pages = iPagination(page_params)
|
||||
offset = (page - 1) * app.config['PAGE_SIZE']
|
||||
list = query.order_by(PayOrder.id.desc()).offset(offset).limit(app.config['PAGE_SIZE']).all()
|
||||
|
||||
stat_info = db.session.query( PayOrder,func.sum( PayOrder.total_price ).label("total") )\
|
||||
.filter( PayOrder.status == 1 ).first()
|
||||
|
||||
app.logger.info ( stat_info )
|
||||
resp_data['list'] = list
|
||||
resp_data['pages'] = pages
|
||||
resp_data['total_money'] = stat_info[ 1 ] if stat_info[ 1 ] else 0.00
|
||||
resp_data['current'] = 'account'
|
||||
return ops_render( "finance/account.html",resp_data )
|
||||
|
||||
|
||||
@route_finance.route("/ops", methods=[ "POST"])
|
||||
def orderOps():
|
||||
resp = {'code': 200, 'msg': '操作成功~', 'data': {}}
|
||||
req = request.values
|
||||
id = req['id'] if 'id' in req else 0
|
||||
act = req['act'] if 'act' in req else ''
|
||||
pay_order_info = PayOrder.query.filter_by( id = id ).first()
|
||||
if not pay_order_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "系统繁忙。请稍后再试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
if act == "express":
|
||||
pay_order_info.express_status = -6
|
||||
pay_order_info.updated_time = getCurrentDate()
|
||||
db.session.add( pay_order_info )
|
||||
db.session.commit()
|
||||
|
||||
return jsonify(resp)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from flask import Blueprint,request,jsonify,redirect
|
||||
from common.libs.Helper import ops_render,getCurrentDate,iPagination,getDictFilterField
|
||||
from application import app,db
|
||||
from common.models.food.Food import Food
|
||||
from common.libs.Helper import ops_render
|
||||
from common.models.food.FoodCat import FoodCat
|
||||
from application import app,db
|
||||
from common.libs.Helper import getCurrentDate,iPagination,getDictFilterField
|
||||
from common.libs.food.FoodService import FoodService
|
||||
from common.models.food.FoodStockChangeLog import FoodStockChangeLog
|
||||
from common.libs.UrlManager import UrlManager
|
||||
from common.libs.food.FoodService import FoodService
|
||||
from decimal import Decimal
|
||||
from sqlalchemy import or_
|
||||
route_food = Blueprint( 'food_page',__name__ )
|
||||
@@ -48,10 +48,27 @@ def index():
|
||||
resp_data['current'] = 'index'
|
||||
return ops_render( "food/index.html",resp_data )
|
||||
|
||||
|
||||
@route_food.route( "/info" )
|
||||
def info():
|
||||
return ops_render( "food/info.html" )
|
||||
resp_data = {}
|
||||
req = request.args
|
||||
id = int(req.get("id", 0))
|
||||
reback_url = UrlManager.buildUrl("/food/index")
|
||||
|
||||
if id < 1:
|
||||
return redirect( reback_url )
|
||||
|
||||
info = Food.query.filter_by( id =id ).first()
|
||||
if not info:
|
||||
return redirect( reback_url )
|
||||
|
||||
stock_change_list = FoodStockChangeLog.query.filter( FoodStockChangeLog.food_id == id )\
|
||||
.order_by( FoodStockChangeLog.id.desc() ).all()
|
||||
|
||||
resp_data['info'] = info
|
||||
resp_data['stock_change_list'] = stock_change_list
|
||||
resp_data['current'] = 'index'
|
||||
return ops_render( "food/info.html",resp_data )
|
||||
|
||||
|
||||
@route_food.route( "/set" ,methods = [ 'GET','POST'] )
|
||||
@@ -59,16 +76,16 @@ def set():
|
||||
if request.method == "GET":
|
||||
resp_data = {}
|
||||
req = request.args
|
||||
id = int(req.get('id', 0))
|
||||
info = Food.query.filter_by(id=id).first()
|
||||
id = int( req.get('id',0) )
|
||||
info = Food.query.filter_by( id = id ).first()
|
||||
if info and info.status != 1:
|
||||
return redirect(UrlManager.buildUrl("/food/index"))
|
||||
return redirect( UrlManager.buildUrl("/food/index") )
|
||||
|
||||
cat_list = FoodCat.query.all()
|
||||
resp_data['info'] = info
|
||||
resp_data['cat_list'] = cat_list
|
||||
resp_data['current'] = 'index'
|
||||
return ops_render("food/set.html", resp_data)
|
||||
return ops_render( "food/set.html" ,resp_data)
|
||||
|
||||
resp = {'code': 200, 'msg': '操作成功~~', 'data': {}}
|
||||
req = request.values
|
||||
@@ -121,6 +138,9 @@ def set():
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请输入标签,便于搜索~~"
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
|
||||
food_info = Food.query.filter_by(id=id).first()
|
||||
before_stock = 0
|
||||
if food_info:
|
||||
@@ -143,7 +163,7 @@ def set():
|
||||
db.session.add(model_food)
|
||||
ret = db.session.commit()
|
||||
|
||||
FoodService.setStockChangeLog(model_food.id, int(stock) - int(before_stock), "后台修改")
|
||||
FoodService.setStockChangeLog( model_food.id,int(stock) - int(before_stock),"后台修改" )
|
||||
return jsonify(resp)
|
||||
|
||||
|
||||
@@ -163,7 +183,6 @@ def cat():
|
||||
resp_data['current'] = 'cat'
|
||||
return ops_render( "food/cat.html",resp_data )
|
||||
|
||||
|
||||
@route_food.route( "/cat-set",methods = [ "GET","POST" ] )
|
||||
def catSet():
|
||||
if request.method == "GET":
|
||||
@@ -202,7 +221,6 @@ def catSet():
|
||||
db.session.commit()
|
||||
return jsonify( resp )
|
||||
|
||||
|
||||
@route_food.route("/cat-ops",methods = [ "POST" ])
|
||||
def catOps():
|
||||
resp = {'code': 200, 'msg': '操作成功~~', 'data': {}}
|
||||
@@ -235,3 +253,38 @@ def catOps():
|
||||
db.session.add( food_cat_info )
|
||||
db.session.commit()
|
||||
return jsonify(resp)
|
||||
|
||||
@route_food.route("/ops",methods=["POST"])
|
||||
def ops():
|
||||
resp = { 'code':200,'msg':'操作成功~~','data':{} }
|
||||
req = request.values
|
||||
|
||||
id = req['id'] if 'id' in req else 0
|
||||
act = req['act'] if 'act' in req else ''
|
||||
|
||||
if not id :
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "请选择要操作的账号~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if act not in [ 'remove','recover' ]:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "操作有误,请重试~~"
|
||||
return jsonify(resp)
|
||||
|
||||
food_info = Food.query.filter_by( id = id ).first()
|
||||
if not food_info:
|
||||
resp['code'] = -1
|
||||
resp['msg'] = "指定美食不存在~~"
|
||||
return jsonify(resp)
|
||||
|
||||
if act == "remove":
|
||||
food_info.status = 0
|
||||
elif act == "recover":
|
||||
food_info.status = 1
|
||||
|
||||
food_info.updated_time = getCurrentDate()
|
||||
db.session.add(food_info)
|
||||
db.session.commit()
|
||||
return jsonify( resp )
|
||||
|
||||
|
||||
63
web/interceptors/ApiAuthInterceptor.py
Normal file
63
web/interceptors/ApiAuthInterceptor.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from application import app
|
||||
from flask import request,g,jsonify
|
||||
|
||||
from common.models.member.Member import Member
|
||||
from common.libs.member.MemberService import MemberService
|
||||
import re
|
||||
|
||||
'''
|
||||
api认证
|
||||
'''
|
||||
@app.before_request
|
||||
def before_request_api():
|
||||
api_ignore_urls = app.config['API_IGNORE_URLS']
|
||||
|
||||
path = request.path
|
||||
if '/api' not in path:
|
||||
return
|
||||
|
||||
member_info = check_member_login()
|
||||
g.member_info = None
|
||||
if member_info:
|
||||
g.member_info = member_info
|
||||
|
||||
pattern = re.compile('%s' % "|".join( api_ignore_urls ))
|
||||
if pattern.match(path):
|
||||
return
|
||||
|
||||
if not member_info :
|
||||
resp = {'code': -1, 'msg': '未登录~', 'data': {}}
|
||||
return jsonify(resp)
|
||||
|
||||
return
|
||||
|
||||
|
||||
'''
|
||||
判断用户是否已经登录
|
||||
'''
|
||||
def check_member_login():
|
||||
auth_cookie = request.headers.get("Authorization")
|
||||
|
||||
if auth_cookie is None:
|
||||
return False
|
||||
|
||||
auth_info = auth_cookie.split("#")
|
||||
if len(auth_info) != 2:
|
||||
return False
|
||||
|
||||
try:
|
||||
member_info = Member.query.filter_by(id=auth_info[1]).first()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
if member_info is None:
|
||||
return False
|
||||
|
||||
if auth_info[0] != MemberService.geneAuthCode( member_info ):
|
||||
return False
|
||||
|
||||
if member_info.status != 1:
|
||||
return False
|
||||
|
||||
return member_info
|
||||
16
web/static/js/finance/index.js
Normal file
16
web/static/js/finance/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
;
|
||||
var finance_index_ops = {
|
||||
init:function(){
|
||||
this.eventBind();
|
||||
},
|
||||
eventBind:function(){
|
||||
var that = this;
|
||||
$(".wrap_search select[name=status]").change( function(){
|
||||
$(".wrap_search").submit();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready( function(){
|
||||
finance_index_ops.init();
|
||||
});
|
||||
40
web/static/js/finance/pay_info.js
Normal file
40
web/static/js/finance/pay_info.js
Normal file
@@ -0,0 +1,40 @@
|
||||
;
|
||||
var finance_pay_info_ops = {
|
||||
init:function(){
|
||||
this.eventBind();
|
||||
},
|
||||
eventBind:function(){
|
||||
$(".express_send").click(function(){
|
||||
var data_id = $(this).attr("data");
|
||||
var callback = {
|
||||
'ok':function(){
|
||||
$.ajax({
|
||||
url:common_ops.buildUrl( "/finance/ops" ),
|
||||
type:'POST',
|
||||
data:{
|
||||
act:"express",
|
||||
id:data_id
|
||||
},
|
||||
dataType:'json',
|
||||
success:function( res ){
|
||||
var callback = null;
|
||||
if( res.code == 200 ){
|
||||
callback = function(){
|
||||
window.location.href = window.location.href;
|
||||
}
|
||||
}
|
||||
common_ops.alert( res.msg,callback );
|
||||
}
|
||||
});
|
||||
},
|
||||
'cancel':null
|
||||
};
|
||||
common_ops.confirm( "确定已发货了?", callback );
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready( function(){
|
||||
finance_pay_info_ops.init();
|
||||
});
|
||||
|
||||
@@ -56,8 +56,7 @@
|
||||
<div class="row border-bottom">
|
||||
<nav class="navbar navbar-static-top" role="navigation" style="margin-bottom: 0">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="javascript:void(0);"><i
|
||||
class="fa fa-bars"></i> </a>
|
||||
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="javascript:void(0);"><i class="fa fa-bars"></i> </a>
|
||||
</div>
|
||||
<ul class="nav navbar-top-links navbar-right">
|
||||
<li>
|
||||
@@ -67,20 +66,18 @@
|
||||
</li>
|
||||
<li class="dropdown user_info">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0);">
|
||||
<img alt="image" class="img-circle"
|
||||
src="{{ buildStaticUrl('/images/common/avatar.png') }}"/>
|
||||
<img alt="image" class="img-circle" src="{{ buildStaticUrl('/images/common/avatar.png') }}"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-messages">
|
||||
<li>
|
||||
<div class="dropdown-messages-box">
|
||||
姓名:{{current_user.nickname}} <a href="{{ buildUrl('/user/edit') }}"
|
||||
class="pull-right">编辑</a>
|
||||
姓名:{{ current_user.nickname }} <a href="{{ buildUrl('/user/edit') }}" class="pull-right">编辑</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<div class="dropdown-messages-box">
|
||||
手机号码:{{ current_user.mobile}}
|
||||
手机号码:{{ current_user.mobile }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
@@ -108,7 +105,6 @@
|
||||
<input name="domain" value="{{ config.APP.domain }}">
|
||||
<input name="prefix_url" value="{{ config.UPLOAD.prefix_url }}">
|
||||
</div>
|
||||
|
||||
<script src="{{ buildStaticUrl('/plugins/jquery-2.1.1.js') }}"></script>
|
||||
<script src="{{ buildStaticUrl('/bootstrap/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ buildStaticUrl('/plugins/layer/layer.js') }}"></script>
|
||||
|
||||
14
web/templates/common/tab_finance.html
Normal file
14
web/templates/common/tab_finance.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li {% if current == "index" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/finance/index') }}">订单列表</a>
|
||||
</li>
|
||||
<li {% if current == "account" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/finance/account') }}">财务流水</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
14
web/templates/common/tab_member.html
Normal file
14
web/templates/common/tab_member.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li {% if current == "index" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/member/index') }}">会员列表</a>
|
||||
</li>
|
||||
<li {% if current == "comment" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/member/comment') }}">会员评论</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
20
web/templates/common/tab_stat.html
Normal file
20
web/templates/common/tab_stat.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li {% if current == "index" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/stat/index') }}">财务统计</a>
|
||||
</li>
|
||||
<li {% if current == "food" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/stat/food') }}">售卖统计</a>
|
||||
</li>
|
||||
<li {% if current == "member" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/stat/member') }}">会员消费统计</a>
|
||||
</li>
|
||||
<li {% if current == "share" %} class="current" {% endif %}>
|
||||
<a href="{{ buildUrl('/stat/share') }}">分享统计</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,22 +1,9 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li>
|
||||
<a href="{{ buildUrl('/finance/index') }}">订单列表</a>
|
||||
</li>
|
||||
<li class="current">
|
||||
<a href="{{ buildUrl('/finance/account') }}">财务流水</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "common/tab_finance.html" %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 m-t">
|
||||
<p>总收款金额:5.35元</p>
|
||||
<p>总收款金额:{{ total_money }}元</p>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-bordered m-t">
|
||||
@@ -28,21 +15,21 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if list %}
|
||||
{% for item in list %}
|
||||
<tr>
|
||||
<td>20180224387</td>
|
||||
<td>0.05</td>
|
||||
<td>2018-02-24 12:37</td>
|
||||
<td>{{ item.order_number }}</td>
|
||||
<td>{{ item.total_price }}</td>
|
||||
<td>{{ item.pay_time }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr><td colspan="3">暂无数据~~</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<span class="pagination_count" style="line-height: 40px;">共1条记录 | 每页50条</span>
|
||||
<ul class="pagination pagination-lg pull-right" style="margin: 0 0 ;">
|
||||
<li class="active"><a href="javascript:void(0);">1</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!--分页代码已被封装到统一模板文件中-->
|
||||
{% include 'common/pagenation.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="current">
|
||||
<a href="{{ buildUrl('/finance/index') }}">订单列表</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ buildUrl('/finance/account') }}">财务流水</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "common/tab_finance.html" %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<form class="form-inline wrap_search">
|
||||
@@ -21,9 +8,9 @@
|
||||
<div class="form-group">
|
||||
<select name="status" class="form-control inline">
|
||||
<option value="-1">请选择状态</option>
|
||||
<option value="1">已支付</option>
|
||||
<option value="-8">待支付</option>
|
||||
<option value="0">已关闭</option>
|
||||
{% for tmp_key in pay_status_mapping %}
|
||||
<option value="{{ tmp_key }}" {% if tmp_key == search_con['status'] %} selected {% endif %}>{{ pay_status_mapping[ tmp_key ] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -42,33 +29,36 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if list %}
|
||||
{% for item in list %}
|
||||
<tr>
|
||||
<td>20171231347</td>
|
||||
<td>{{ item.order_number }}</td>
|
||||
<td>
|
||||
小鸡炖蘑菇 × 1<br>
|
||||
{% for item_food in item.foods %}
|
||||
{{ item_food.name }} × {{ item_food.quantity }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>0.01</td>
|
||||
<td>{{ item.price }}</td>
|
||||
<td>{{ item.pay_time }}</td>
|
||||
<td>{{ item.status_desc }}</td>
|
||||
<td>{{ item.created_time }}</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>已关闭</td>
|
||||
<td>2017-12-31 13:35</td>
|
||||
<td>
|
||||
<a href="{{ buildUrl('/finance/pay-info') }}">
|
||||
<a href="{{ buildUrl('/finance/pay-info') }}?id={{ item.id }}">
|
||||
<i class="fa fa-eye fa-lg"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr><td colspan="7">暂无数据~~</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<!--分页代码已被封装到统一模板文件中-->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<span class="pagination_count" style="line-height: 40px;">共1条记录 | 每页50条</span>
|
||||
<ul class="pagination pagination-lg pull-right" style="margin: 0 0 ;">
|
||||
<li class="active"><a href="javascript:void(0);">1</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'common/pagenation.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<script src="{{ buildStaticUrl('/js/finance/index.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="current">
|
||||
<a href="{{ buildUrl('/finance/index') }}">订单列表</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ buildUrl('/finance/account') }}">财务流水</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "common/tab_finance.html" %}
|
||||
<div class="row m-t wrap_info">
|
||||
<div class="col-lg-12">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="m-b-md">
|
||||
{% if pay_order_info.status == 1 and pay_order_info.express_status == -7 %}
|
||||
<a class="btn btn-outline btn-primary pull-right express_send" href="javascript:void(0);" data="{{ pay_order_info.id }}">确认发货</a>
|
||||
{% endif %}
|
||||
<div class="m-b-md">
|
||||
<h2>订单信息</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p class="m-t">订单编号:20180605398</p>
|
||||
<p>会员姓名:Mr 杨</p>
|
||||
<p>订单总价:1.00</p>
|
||||
<p>订单状态:已关闭</p>
|
||||
<p>创建时间:2018-06-05 21:13</p>
|
||||
<p>收货地址:北京市海淀区5558855(测试)13145310973</p>
|
||||
<p class="m-t">订单编号:{{ pay_order_info.order_number }}</p>
|
||||
<p>会员姓名:{{ member_info.nickname }}</p>
|
||||
<p>订单总价:{{ pay_order_info.total_price }}</p>
|
||||
<p>订单状态:{{ pay_order_info.status_desc }}</p>
|
||||
<p>创建时间:{{ pay_order_info.created_time }}</p>
|
||||
<p>收货地址:{{ address_info.nickname }},{{ address_info.mobile }},{{ address_info.address }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t">
|
||||
@@ -58,12 +48,14 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>11</td>
|
||||
<td>1</td>
|
||||
<td>1.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{% for item in pay_order_items %}
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.price }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,3 +66,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<script src="{{ buildStaticUrl('/js/finance/pay_info.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
{% include "common/tab_food.html" %}
|
||||
<div class="row">
|
||||
<div class="row">tab_food
|
||||
<div class="col-lg-12">
|
||||
<form class="form-inline wrap_search">
|
||||
<div class="row m-t p-w-m">
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li>
|
||||
<a href="{{ buildUrl('/food/index') }}">美食列表</a>
|
||||
</li>
|
||||
<li class="current">
|
||||
<a href="{{ buildUrl('/food/cat') }}">分类列表</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "common/tab_food.html" %}
|
||||
<div class="row m-t wrap_cat_set">
|
||||
<div class="col-lg-12">
|
||||
<h2 class="text-center">分类设置</h2>
|
||||
@@ -21,7 +8,7 @@
|
||||
<div class="form-group">
|
||||
<label class="col-lg-2 control-label">分类名称:</label>
|
||||
<div class="col-lg-10">
|
||||
<input type="text" name="name" class="form-control" placeholder="请输入分类名称~~" value="info.name">
|
||||
<input type="text" name="name" class="form-control" placeholder="请输入分类名称~~" value="{{ info.name }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
@@ -34,7 +21,7 @@
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-lg-4 col-lg-offset-2">
|
||||
<input type="hidden" name="id" value="{{ info.id }}">
|
||||
<input type="hidden" name="id" value="{{ info.id }}">
|
||||
<button class="btn btn-w-m btn-outline btn-primary save">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
{% extends "common/layout_main.html" %}
|
||||
{% block content %}
|
||||
<div class="row border-bottom">
|
||||
<div class="col-lg-12">
|
||||
<div class="tab_title">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="current">
|
||||
<a href="{{ buildUrl('/food/index') }}">美食列表</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ buildUrl('/food/cat') }}">分类列表</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include "common/tab_food.html" %}
|
||||
<style type="text/css">
|
||||
.wrap_info img {
|
||||
width: 70%;
|
||||
@@ -24,7 +11,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="m-b-md">
|
||||
<a class="btn btn-outline btn-primary pull-right" href="{{ buildUrl('/food/set') }}">
|
||||
<a class="btn btn-outline btn-primary pull-right" href="{{ buildUrl('/food/set') }}?id={{ info.id }}">
|
||||
<i class="fa fa-pencil"></i>编辑
|
||||
</a>
|
||||
<h2>美食信息</h2>
|
||||
@@ -33,13 +20,13 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p class="m-t">美食名:小鸡炖蘑菇</p>
|
||||
<p>售价:45.00</p>
|
||||
<p>库存总量:88</p>
|
||||
<p>图书标签:好吃</p>
|
||||
<p>封面图:<img src="{{ buildStaticUrl('/images/common/logo.png') }}" style="width: 50px;height: 50px;"></p>
|
||||
<p class="m-t">美食名:{{ info.name }}</p>
|
||||
<p>售价:{{ info.price }}</p>
|
||||
<p>库存总量:{{ info.stock }}</p>
|
||||
<p>图书标签:{{ info.tags }}</p>
|
||||
<p>封面图:<img src="{{ buildImageUrl( info.main_image ) }}" style="width: 50px;height: 50px;"></p>
|
||||
<p>描述:</p>
|
||||
<p>小鸡炖蘑菇~~~~</p>
|
||||
<p>{{ info.summary | safe }}</p>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,71 +75,17 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-14 20:00:02</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-14 19:14:32</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-14 10:11:14</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-14 10:10:21</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-12 23:00:02</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-12 22:28:11</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-11 17:00:02</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-11 16:29:48</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-10 14:30:02</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>订单过期释放库存</td>
|
||||
<td>2018-03-10 14:30:02</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-10 13:57:43</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>在线购买</td>
|
||||
<td>2018-03-10 13:56:09</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>88</td>
|
||||
<td></td>
|
||||
<td>2018-03-01 14:40:02</td>
|
||||
</tr>
|
||||
{% if stock_change_list %}
|
||||
{% for item in stock_change_list %}
|
||||
<tr>
|
||||
<td>{{ item.unit }}</td>
|
||||
<td>{{ item.note }}</td>
|
||||
<td>{{ item.created_time }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr><td colspan="3">暂无数据~~</td></tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
17
www.py
17
www.py
@@ -5,29 +5,32 @@ from application import app
|
||||
统一拦截处理和统一错误处理
|
||||
'''
|
||||
from web.interceptors.AuthInterceptor import *
|
||||
from web.interceptors.ApiAuthInterceptor import *
|
||||
from web.interceptors.ErrorInterceptor import *
|
||||
|
||||
'''
|
||||
蓝图功能,对所有的url进行蓝图功能配置
|
||||
'''
|
||||
|
||||
from web.controllers.index import route_index
|
||||
from web.controllers.user.User import route_user
|
||||
from web.controllers.static import route_static
|
||||
from web.controllers.account.Account import route_account
|
||||
from web.controllers.finance.Finance import route_finance
|
||||
|
||||
from web.controllers.food.Food import route_food
|
||||
from web.controllers.account.Account import route_account
|
||||
from web.controllers.member.Member import route_member
|
||||
from web.controllers.finance.Finance import route_finance
|
||||
from web.controllers.stat.Stat import route_stat
|
||||
from web.controllers.api import route_api
|
||||
from web.controllers.upload.Upload import route_upload
|
||||
from web.controllers.chart import route_chart
|
||||
app.register_blueprint( route_index,url_prefix = "/" )
|
||||
app.register_blueprint( route_user,url_prefix = "/user" )
|
||||
app.register_blueprint( route_static,url_prefix = "/static" )
|
||||
app.register_blueprint( route_account,url_prefix = "/account" )
|
||||
app.register_blueprint(route_finance,url_prefix="/finance")
|
||||
app.register_blueprint(route_member,url_prefix="/member")
|
||||
app.register_blueprint(route_food,url_prefix="/food")
|
||||
app.register_blueprint(route_stat,url_prefix="/stat")
|
||||
app.register_blueprint( route_food,url_prefix = "/food" )
|
||||
app.register_blueprint( route_member,url_prefix = "/member" )
|
||||
app.register_blueprint( route_finance,url_prefix = "/finance" )
|
||||
app.register_blueprint( route_stat,url_prefix = "/stat" )
|
||||
app.register_blueprint( route_api,url_prefix = "/api" )
|
||||
app.register_blueprint( route_upload,url_prefix = "/upload" )
|
||||
app.register_blueprint( route_chart,url_prefix = "/chart" )
|
||||
|
||||
Reference in New Issue
Block a user