from . import api from flask import g, current_app, jsonify, request, session from ihome.utils.response_code import RET from ihome.models import Area, House, Facility, HouseImage, User, Order from ihome import db, constants, redis_store from ihome.utils.commons import login_required from ihome.utils.image_storage import storage from datetime import datetime import json # GET /api/v1.0/houses?sd=2017-12-01&ed=2017-12-31&aid=10&sk=new&p=1 @api.route("/houses") def get_house_list(): """Get listing information for houses (search page)""" start_date = request.args.get("sd", "") # The user's desired start time end_date = request.args.get("ed", "") # End time desired by the user area_id = request.args.get("aid", "") # Area Number sort_key = request.args.get("sk", "new") # Sort keywords page = request.args.get("p") # The number of pages # processing time try: if start_date: start_date = datetime.strptime(start_date, "%Y-%m-%d") if end_date: end_date = datetime.strptime(end_date, "%Y-%m-%d") if start_date and end_date: assert start_date <= end_date except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.PARAMERR, errmsg="Error in date parameter") # Judgement area id if area_id: try: area = Area.query.get(area_id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.PARAMERR, errmsg="Error in area parameter") # Processing Pages try: page = int(page) except Exception as e: current_app.logger.error(e) page = 1 # Get Cached Data redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key) try: resp_json = redis_store.hget(redis_key, page) except Exception as e: current_app.logger.error(e) else: if resp_json: return resp_json, 200, {"Content-Type": "application/json"} # Parameter List Container for Filter Conditions filter_params = [] # Fill filter parameters # Time conditions conflict_orders = None try: if start_date and end_date: # Query Conflicting Orders conflict_orders = Order.query.filter(Order.begin_date <= end_date, Order.end_date >= start_date).all() elif start_date: conflict_orders = Order.query.filter(Order.end_date >= start_date).all() elif end_date: conflict_orders = Order.query.filter(Order.begin_date <= end_date).all() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Database Exception") if conflict_orders: # Get the conflicting house id from the order conflict_house_ids = [order.house_id for order in conflict_orders] # If the conflicting house id is not empty, add a condition to the query parameter if conflict_house_ids: filter_params.append(House.id.notin_(conflict_house_ids)) # Regional conditions if area_id: filter_params.append(House.area_id == area_id) # query data base # Supplemental Sorting Conditions if sort_key == "booking": # Check in too much house_query = House.query.filter(*filter_params).order_by(House.order_count.desc()) elif sort_key == "price-inc": house_query = House.query.filter(*filter_params).order_by(House.price.asc()) elif sort_key == "price-des": house_query = House.query.filter(*filter_params).order_by(House.price.desc()) else: # old and new house_query = House.query.filter(*filter_params).order_by(House.create_time.desc()) # Processing Paging try: # Current Pages Automatically Error Output Per Page page_obj = house_query.paginate(page=page, per_page=constants.HOUSE_LIST_PAGE_CAPACITY, error_out=False) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Database Exception") # Get Page Data house_li = page_obj.items houses = [] for house in house_li: houses.append(house.to_basic_dict()) # Get total pages total_page = page_obj.pages resp_dict = dict(errno=RET.OK, errmsg="OK", data={"total_page": total_page, "houses": houses, "current_page": page}) resp_json = json.dumps(resp_dict) if page <= total_page: # Setting up cached data redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key) # Hash Type try: # redis_store.hset(redis_key, page, resp_json) # redis_store.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES) # Create a redis pipeline object that can execute multiple statements at once pipeline = redis_store.pipeline() # Open records for multiple statements pipeline.multi() pipeline.hset(redis_key, page, resp_json) pipeline.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES) # Execute Statement pipeline.execute() except Exception as e: current_app.logger.error(e) return resp_json, 200, {"Content-Type": "application/json"} # redis_store # # "house_start_end_region id_sort_page number" # (errno=RET.OK, errmsg="OK", data={"total_page": total_page, "houses": houses, "current_page": page}) # # # # "house_start_end_region id_sort": hash # { # "1": "{}", # "2": "{}", # }
Front end js
var cur_page = 1; // Current Page var next_page = 1; // next page var total_page = 1; // PageCount var house_data_querying = true; // Is data being retrieved from the background // Parsing query strings in URLs function decodeQuery(){ var search = decodeURI(document.location.search); return search.replace(/(^\?)/, '').split('&').reduce(function(result, item){ values = item.split('='); result[values[0]] = values[1]; return result; }, {}); } // Update user-selected filter criteria function updateFilterDateDisplay() { var startDate = $("#start-date").val(); var endDate = $("#end-date").val(); var $filterDateTitle = $(".filter-title-bar>.filter-title").eq(0).children("span").eq(0); if (startDate) { var text = startDate.substr(5) + "/" + endDate.substr(5); $filterDateTitle.html(text); } else { $filterDateTitle.html("Date of stay"); } } // Update House Source List Information // action represents how data requested from the backend is presented on the front end // Append by default // action=renew stands for page data empty from new display function updateHouseData(action) { var areaId = $(".filter-area>li.active").attr("area-id"); if (undefined == areaId) areaId = ""; var startDate = $("#start-date").val(); var endDate = $("#end-date").val(); var sortKey = $(".filter-sort>li.active").attr("sort-key"); var params = { aid:areaId, sd:startDate, ed:endDate, sk:sortKey, p:next_page }; $.get("/api/v1.0/houses", params, function(resp){ house_data_querying = false; if ("0" == resp.errno) { if (0 == resp.data.total_page) { $(".house-list").html("There is currently no house information that matches your query."); } else { total_page = resp.data.total_page; if ("renew" == action) { cur_page = 1; $(".house-list").html(template("house-list-tmpl", )); } else { cur_page = next_page; $(".house-list").append(template("house-list-tmpl", )); } } } }) } $(document).ready(function(){ var queryData = decodeQuery(); var startDate = queryData["sd"]; var endDate = queryData["ed"]; $("#start-date").val(startDate); $("#end-date").val(endDate); updateFilterDateDisplay(); var areaName = queryData["aname"]; if (!areaName) areaName = "Location area"; $(".filter-title-bar>.filter-title").eq(1).children("span").eq(0).html(areaName); // Getting City area information in filter criteria $.get("/api/v1.0/areas", function(data){ if ("0" == data.errno) { // Users may choose urban areas when they jump from the home page to this search page, so try to extract the urban areas they choose from the url's query string parameters var areaId = queryData["aid"]; // If the data for urban id is extracted if (areaId) { // Walk through the city information you get from the back end and add it to the page for (var i=0; i<data.data.length; i++) { // Highlight urban areas from url query string parameters on the page // The backend gets the city id as an integer and the url parameter gets the string type, so convert the url parameter into an integer and compare areaId = parseInt(areaId); if (data.data[i].aid == areaId) { $(".filter-area").append('<li area-id="'+ data.data[i].aid+'">'+ data.data[i].aname+'</li>'); } else { $(".filter-area").append('<li area-id="'+ data.data[i].aid+'">'+ data.data[i].aname+'</li>'); } } } else { // If there is no urban information in the url parameter, no additional processing is required and the traversal is displayed directly on the page for (var i=0; i<data.data.length; i++) { $(".filter-area").append('<li area-id="'+ data.data[i].aid+'">'+ data.data[i].aname+'</li>'); } } // Update the display house list information after adding urban option information to the page updateHouseData("renew"); // Get the height of the page display window var windowHeight = $(window).height(); // Add event functions for window scrolling window.onscroll=function(){ // var a = document.documentElement.scrollTop==0? document.body.clientHeight : document.documentElement.clientHeight; var b = document.documentElement.scrollTop==0? document.body.scrollTop : document.documentElement.scrollTop; var c = document.documentElement.scrollTop==0? document.body.scrollHeight : document.documentElement.scrollHeight; // If you scroll close to the bottom of the window if(c-b<windowHeight+50){ // If no request is being sent to the back end for housing list information if (!house_data_querying) { // Set the flag that is querying the backend for house list information to true, house_data_querying = true; // If the current number of pages has not reached the total number of pages if(cur_page < total_page) { // Set the number of pages to be queried to the current number of pages plus 1 next_page = cur_page + 1; // Send a request to the back end to query the next page of housing data updateHouseData(); } else { house_data_querying = false; } } } } } }); $(".input-daterange").datepicker({ format: "yyyy-mm-dd", startDate: "today", language: "zh-CN", autoclose: true }); var $filterItem = $(".filter-item-bar>.filter-item"); $(".filter-title-bar").on("click", ".filter-title", function(e){ var index = $(this).index(); if (!$filterItem.eq(index).hasClass("active")) { $(this).children("span").children("i").removeClass("fa-angle-down").addClass("fa-angle-up"); $(this).siblings(".filter-title").children("span").children("i").removeClass("fa-angle-up").addClass("fa-angle-down"); $filterItem.eq(index).addClass("active").siblings(".filter-item").removeClass("active"); $(".display-mask").show(); } else { $(this).children("span").children("i").removeClass("fa-angle-up").addClass("fa-angle-down"); $filterItem.eq(index).removeClass('active'); $(".display-mask").hide(); updateFilterDateDisplay(); } }); $(".display-mask").on("click", function(e) { $(this).hide(); $filterItem.removeClass('active'); updateFilterDateDisplay(); cur_page = 1; next_page = 1; total_page = 1; updateHouseData("renew"); }); $(".filter-item-bar>.filter-area").on("click", "li", function(e) { if (!$(this).hasClass("active")) { $(this).addClass("active"); $(this).siblings("li").removeClass("active"); $(".filter-title-bar>.filter-title").eq(1).children("span").eq(0).html($(this).html()); } else { $(this).removeClass("active"); $(".filter-title-bar>.filter-title").eq(1).children("span").eq(0).html("Location area"); } }); $(".filter-item-bar>.filter-sort").on("click", "li", function(e) { if (!$(this).hasClass("active")) { $(this).addClass("active"); $(this).siblings("li").removeClass("active"); $(".filter-title-bar>.filter-title").eq(2).children("span").eq(0).html($(this).html()); } }) })Order
# coding:utf-8 import datetime from flask import request, g, jsonify, current_app from ihome import db, redis_store from ihome.utils.commons import login_required from ihome.utils.response_code import RET from ihome.models import House, Order from . import api @api.route("/orders", methods=["POST"]) @login_required def save_order(): """Save Order""" user_id = g.user_id # Get parameters order_data = request.get_json() if not order_data: return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") house_id = order_data.get("house_id") # Reserved House Number start_date_str = order_data.get("start_date") # Booking Start Time end_date_str = order_data.get("end_date") # End time of booking # Parameter Check if not all((house_id, start_date_str, end_date_str)): return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") # Date Format Check try: # Convert requested time parameter string to datetime type start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d") end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d") assert start_date <= end_date # Calculate days of booking days = (end_date - start_date).days + 1 # datetime.timedelta except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.PARAMERR, errmsg="Date format error") # Query if a house exists try: house = House.query.get(house_id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Failed to get house information") if not house: return jsonify(errno=RET.NODATA, errmsg="House does not exist") # Is the booked house the owner's own if user_id == house.user_id: return jsonify(errno=RET.ROLEERR, errmsg="You can't book your own house") # Make sure that no one else orders the house for the time the user has booked try: # Number of orders querying for time conflicts count = Order.query.filter(Order.house_id == house_id, Order.begin_date <= end_date, Order.end_date >= start_date).count() # select count(*) from order where .... except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Check for errors, please try again later") if count > 0: return jsonify(errno=RET.DATAERR, errmsg="The house has been reserved") # Total Order amount = days * house.price # Save order data order = Order( house_id=house_id, user_id=user_id, begin_date=start_date, end_date=end_date, days=days, house_price=house.price, amount=amount ) try: db.session.add(order) db.session.commit() except Exception as e: current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.DBERR, errmsg="Failed to save order") return jsonify(errno=RET.OK, errmsg="OK", data={"order_id": order.id}) # /api/v1.0/user/orders?role=custom role=landlord @api.route("/user/orders", methods=["GET"]) @login_required def get_user_orders(): """Query user's order information""" user_id = g.user_id # Identity of the user, who wants to query an order to reserve another person's house as a tenant or an order to reserve his own house as a landowner role = request.args.get("role", "") # Query order data try: if "landlord" == role: # Query orders as landlord # Query first what houses you own houses = House.query.filter(House.user_id == user_id).all() houses_ids = [house.id for house in houses] # Re-query orders for your own house orders = Order.query.filter(Order.house_id.in_(houses_ids)).order_by(Order.create_time.desc()).all() else: # Query orders as tenants and self-booked orders orders = Order.query.filter(Order.user_id == user_id).order_by(Order.create_time.desc()).all() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Failed to query order information") # Convert Order Object to Dictionary Data orders_dict_list = [] if orders: for order in orders: orders_dict_list.append(order.to_dict()) return jsonify(errno=RET.OK, errmsg="OK", data={"orders": orders_dict_list}) @api.route("/orders/<int:order_id>/status", methods=["PUT"]) @login_required def accept_reject_order(order_id): """Acceptance, rejection""" user_id = g.user_id # Get parameters req_data = request.get_json() if not req_data: return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") # The action parameter indicates whether the client requested an order or a rejection behavior action = req_data.get("action") if action not in ("accept", "reject"): return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") try: # Query orders based on order number and require orders to be in a waiting state order = Order.query.filter(Order.id == order_id, Order.status == "WAIT_ACCEPT").first() house = order.house except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Unable to get order data") # Make sure landlords can only modify orders for their own houses if not order or house.user_id != user_id: return jsonify(errno=RET.REQERR, errmsg="Invalid operation") if action == "accept": # Accept orders, set order status to wait for comments order.status = "WAIT_PAYMENT" elif action == "reject": # Rejection, requiring user to pass reason for rejection reason = req_data.get("reason") if not reason: return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") order.status = "REJECTED" order.comment = reason try: db.session.add(order) db.session.commit() except Exception as e: current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.DBERR, errmsg="operation failed") return jsonify(errno=RET.OK, errmsg="OK") @api.route("/orders/<int:order_id>/comment", methods=["PUT"]) @login_required def save_order_comment(order_id): """Save order comment information""" user_id = g.user_id # Get parameters req_data = request.get_json() comment = req_data.get("comment") # Evaluation Information # Check parameters if not comment: return jsonify(errno=RET.PARAMERR, errmsg="Parameter error") try: # You need to make sure that you can only comment on your order and that it is pending evaluation order = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status == "WAIT_COMMENT").first() house = order.house except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Unable to get order data") if not order: return jsonify(errno=RET.REQERR, errmsg="Invalid operation") try: # Set the status of the order to Completed order.status = "COMPLETE" # Save order evaluation information order.comment = comment # Increase the number of completed housing orders by 1 house.order_count += 1 db.session.add(order) db.session.add(house) db.session.commit() except Exception as e: current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.DBERR, errmsg="operation failed") # Because the house details contain the evaluation information of the order, in order to let the latest evaluation information be displayed in the house details, delete the details cache in redis for this order house try: redis_store.delete("house_info_%s" % order.house.id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.OK, errmsg="OK")
Front part
order.js
//Control of Modal Frame Centering function centerModals(){ $('.modal').each(function(i){ //Traverse through each modal box var $clone = $(this).clone().css('display', 'block').appendTo('body'); var top = Math.round(($clone.height() - $clone.find('.modal-content').height()) / 2); top = top > 0 ? top : 0; $clone.remove(); $(this).find('.modal-content').css("margin-top", top-30); //Correct the original 30 pixels }); } function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } $(document).ready(function(){ $('.modal').on('show.bs.modal', centerModals); //When the modal box appears $(window).on('resize', centerModals); // Query tenant orders $.get("/api/v1.0/user/orders?role=custom", function(resp){ if ("0" == resp.errno) { $(".orders-list").html(template("orders-list-tmpl", )); $(".order-pay").on("click", function () { var orderId = $(this).parents("li").attr("order-id"); $.ajax({ url: "/api/v1.0/orders/" + orderId + "/payment", type: "post", dataType: "json", headers: { "X-CSRFToken": getCookie("csrf_token"), }, success: function (resp) { if ("4101" == resp.errno) { location.href = "/login.html"; } else if ("0" == resp.errno) { // Guide users to Alipay connection location.href = resp.data.pay_url; } } }); }); $(".order-comment").on("click", function(){ var orderId = $(this).parents("li").attr("order-id"); $(".modal-comment").attr("order-id", orderId); }); $(".modal-comment").on("click", function(){ var orderId = $(this).attr("order-id"); var comment = $("#comment").val() if (!comment) return; var data = { order_id:orderId, comment:comment }; // Processing comments $.ajax({ url:"/api/v1.0/orders/"+orderId+"/comment", type:"PUT", data:JSON.stringify(data), contentType:"application/json", dataType:"json", headers:{ "X-CSRFTOKEN":getCookie("csrf_token"), }, success:function (resp) { if ("4101" == resp.errno) { location.href = "/login.html"; } else if ("0" == resp.errno) { $(".orders-list>li[order-id="+ orderId +"]>div.order-content>div.order-text>ul li:eq(4)>span").html("Completed"); $("ul.orders-list>li[order-id="+ orderId +"]>div.order-title>div.order-operate").hide(); $("#comment-modal").modal("hide"); } } }); }); } }); });
lorder.js
//Control of Modal Frame Centering function centerModals(){ $('.modal').each(function(i){ //Traverse through each modal box var $clone = $(this).clone().css('display', 'block').appendTo('body'); var top = Math.round(($clone.height() - $clone.find('.modal-content').height()) / 2); top = top > 0 ? top : 0; $clone.remove(); $(this).find('.modal-content').css("margin-top", top-30); //Correct the original 30 pixels }); } function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } $(document).ready(function(){ $('.modal').on('show.bs.modal', centerModals); //When the modal box appears $(window).on('resize', centerModals); // Query landlord's order $.get("/api/v1.0/user/orders?role=landlord", function(resp){ if ("0" == resp.errno) { $(".orders-list").html(template("orders-list-tmpl", )); $(".order-accept").on("click", function(){ var orderId = $(this).parents("li").attr("order-id"); $(".modal-accept").attr("order-id", orderId); }); // Order handling $(".modal-accept").on("click", function(){ var orderId = $(this).attr("order-id"); $.ajax({ url:"/api/v1.0/orders/"+orderId+"/status", type:"PUT", data:'{"action":"accept"}', contentType:"application/json", dataType:"json", headers:{ "X-CSRFTOKEN":getCookie("csrf_token"), }, success:function (resp) { if ("4101" == resp.errno) { location.href = "/login.html"; } else if ("0" == resp.errno) { $(".orders-list>li[order-id="+ orderId +"]>div.order-content>div.order-text>ul li:eq(4)>span").html("Accepted Order"); $("ul.orders-list>li[order-id="+ orderId +"]>div.order-title>div.order-operate").hide(); $("#accept-modal").modal("hide"); } } }) }); $(".order-reject").on("click", function(){ var orderId = $(this).parents("li").attr("order-id"); $(".modal-reject").attr("order-id", orderId); }); // Handle rejection $(".modal-reject").on("click", function(){ var orderId = $(this).attr("order-id"); var reject_reason = $("#reject-reason").val(); if (!reject_reason) return; var data = { action: "reject", reason:reject_reason }; $.ajax({ url:"/api/v1.0/orders/"+orderId+"/status", type:"PUT", data:JSON.stringify(data), contentType:"application/json", headers: { "X-CSRFTOKEN":getCookie("csrf_token") }, dataType:"json", success:function (resp) { if ("4101" == resp.errno) { location.href = "/login.html"; } else if ("0" == resp.errno) { $(".orders-list>li[order-id="+ orderId +"]>div.order-content>div.order-text>ul li:eq(4)>span").html("Rejected"); $("ul.orders-list>li[order-id="+ orderId +"]>div.order-title>div.order-operate").hide(); $("#reject-modal").modal("hide"); } } }); }) } }); });Docking Alipay
-
Alipay Open Platform Login
Use an existing Payment Account
https://open.alipay.com/platform/home.htm -
About sandbox environments (development simulation environments)
-
https://docs.open.alipay.com/200/105311
After logging in, you can choose to enter the Sandbox Environment Settings page at the top of the page
-
Alipay Developer Documentation
https://openhome.alipay.com/developmentDocument.htm
Mobile Website Payment
https://docs.open.alipay.com/203/105285/ -
Mobile website payment process
5. Signature
Requests sent to pay require signature
https://docs.open.alipay.com/291/106118
- Using the python Toolkit
https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
install
# For users upgraded from 1.3.0, please uninstall pycrypto: pip uninstall pycrypto # Install python-alipay-sdk pip install python-alipay-sdk --upgrade
Generate key file
openssl OpenSSL> genrsa -out app_private_key.pem 2048 # private key OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # Export Public Key OpenSSL> exit
cat app_publict_key.pem View the contents of the public key
Save the contents in the middle of ----- BEGIN PUBLIC KEY - --- and - --- END PUBLIC KEY - --- in Alipay's user configuration (sandbox or formal)
https://openhome.alipay.com/platform/appDaily.htm?tab=info
Download Alipay's public key file
Copy and save the contents of the public key to a text file (alipay_pubilc_key.pem), note that you need to add markup bits (----- BEGIN PUBLIC KEY--- and - --- END PUBLIC KEY---) at the beginning and end of the text, such as:
The private key app_that will just be generated Private_ Key.pem and Alipay public key alipay_ Public_ Put key.pem in our project directory
Initialization using Alipay python package
- Payment interface
# coding:utf-8 from . import api from ihome.utils.commons import login_required from ihome.models import Order from flask import g, current_app, jsonify, request from ihome.utils.response_code import RET from alipay import AliPay from ihome import constants, db import os @api.route("/orders/<int:order_id>/payment", methods=["POST"]) @login_required def order_pay(order_id): """Initiate Alipay Payment""" user_id = g.user_id # Determine order status try: order = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status == "WAIT_PAYMENT").first() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="Database Exception") if order is None: return jsonify(errno=RET.NODATA, errmsg="Error in order data") # Create tool object for Alipay sdk alipay_client = AliPay( appid="2016081600258081", app_notify_url=None, # Default callback url app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"), # private key alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"), # Alipay's public key, verify Alipay return message use, not your own public key, sign_type="RSA2", # RSA or RSA2 debug=True # Default False ) # Mobile website payment, need to jump to https://openapi.alipaydev.com/gateway.do? + order_string order_string = alipay_client.api_alipay_trade_wap_pay( out_trade_no=order.id, # Order Number total_amount=str(order.amount/100.0), # Total amount subject=u"Home-friendly rental %s" % order.id, # Order Title return_url="http://127.0.0.1:5000/payComplete.html ", #Return connection address notify_url=None # Optional, use default notify url if not filled in ) # Build payment connection addresses that let users jump pay_url = constants.ALIPAY_URL_PREFIX + order_string return jsonify(errno=RET.OK, errmsg="OK", data={"pay_url": pay_url}) @api.route("/order/payment", methods=["PUT"]) def save_order_payment_result(): """Save order payment results""" alipay_dict = request.form.to_dict() # Separate Alipay's data to extract Alipay's signature parameter sign and other remaining data alipay_sign = alipay_dict.pop("sign") # Create tool object for Alipay sdk alipay_client = AliPay( appid="2016081600258081", app_notify_url=None, # Default callback url app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"), # private key alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"), # Alipay's public key, verify Alipay return message use, not your own public key, sign_type="RSA2", # RSA or RSA2 debug=True # Default False ) # Validate the validity of parameters with tools # Return True if the parameter is Alipay or false otherwise result = alipay_client.verify(alipay_dict, alipay_sign) if result: # Modify order status information for database order_id = alipay_dict.get("out_trade_no") trade_no = alipay_dict.get("trade_no") # Alipay's Trade Number try: Order.query.filter_by(id=order_id).update({"status": "WAIT_COMMENT", "trade_no": trade_no}) db.session.commit() except Exception as e: current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.OK, errmsg="OK")Database optimization
a. Table structure design Extended query speed
Three Paradigms https://www.zhihu.com/question/24696366
Consider queries that may be used when designing, such as swapping space for time, adding redundant fields appropriately to save query overhead
b. Indexing Primary Key Unique Index (foreign key)
http://www.jianshu.com/p/2b541c028157
Increase Query Speed Composite Index Wherek1 K2 K3 K4
Reduce additions and deletions
c. sql statement optimization
Use index to note the leftmost principle of keyword order where
No select * Ability to use federated queries without nesting (subqueries) select from tbl_a a inner join tbl_b b on a.field=b.filed where b.= select from tbl_a where filed=(select field from tbl_b where b.=) Can not use federated queries, try not to use federated queries foreign key cascade When cascading (extra overhead for maintaining foreign keys, which affects performance) data is large, foreign keys are no longer used Using analysis tools to analyze inefficient sql Statement Slow Query Tool https://flyerboy.github.io/2016/12/23/mysql_slow/ https://yemengying.com/2016/05/24/mysql-tuning/
d. Caching
redis memcached
e. Read-write separation
Master-Slave Hot Backup Master (Write Add Delete Change) Slave (Check)
f. Repository Subtable Horizontal Repository Subtable
http://www.infoq.com/cn/articles/key-steps-and-likely-problems-of-split-table
Workflow
- git gitlab account rsa
- vpn virtual private network Ali Cloud Tencent Cloud aws Amazon
- data base
How many people are on the company team
Which business will I be responsible for when I enter the company?
Technology stack used by the company
https://moshuqi.github.io/2017/07/20/%E8%87%AA%E5%B7%B1%E6%90%AD%E5%BB%BAVPN%E6%9C%8D%E5%8A%A1%E5%99%A8/