Flask project housing list page, orders, docking Alipay, database optimization

House List Page



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", {houses:resp.data.houses}));
                } else {
                    cur_page = next_page;
                    $(".house-list").append(template("house-list-tmpl", {houses: resp.data.houses}));
                }
            }
        }
    })
}

$(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+'" class="active">'+ 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", {orders:resp.data.orders}));
            $(".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", {orders:resp.data.orders}));
            $(".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

  1. Alipay Open Platform Login
    Use an existing Payment Account
    https://open.alipay.com/platform/home.htm

  2. About sandbox environments (development simulation environments)


  3. 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

  1. Alipay Developer Documentation
    https://openhome.alipay.com/developmentDocument.htm
    Mobile Website Payment
    https://docs.open.alipay.com/203/105285/

  2. Mobile website payment process


5. Signature

Requests sent to pay require signature
https://docs.open.alipay.com/291/106118

  1. 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

  1. 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

  1. email
  2. git gitlab account rsa
  3. vpn virtual private network Ali Cloud Tencent Cloud aws Amazon
  4. 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/

Tags: Database Back-end Flask

Posted on Wed, 17 Nov 2021 12:09:18 -0500 by altergothen