Grails 和 PayPal(快速结帐)

发布于 2024-10-14 20:47:03 字数 326 浏览 6 评论 0原文

Grails 有两个 PayPal 插件,我发现的第一个已经有一年了,而且似乎秩序井然。 第二个版本有点旧,显然与 1.1+ 不兼容

如果我决定不使用现有插件,那么为 Grails 实现简单的 Express Checkout 流程的最佳方法是什么?我不完全确定如何使用 PayPal API,并且随着迁移到 X.com,他们的文档目前非常混乱。

There are two PayPal plugins for Grails, the first I found is a year old and seems to be in well enough order. The second it a bit older and apparently not compatible with 1.1+.

If I decide to not use an existing plugin what is the best way to implement a simple Express Checkout flow for Grails? I'm not entirely sure what goes into working with the PayPal API, and their documents are quite the mess at the moment with the move to X.com.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

智商已欠费 2024-10-21 20:47:03

这是我从 Paypal 插件中透露的 IPNcontroller,以满足 Paypal IPN 要求。它正在生产中。

package com.risguru.plugin.ipn

import com.risguru.plugin.shoppingcart.IOrderService

class PaymentController {

IOrderService orderService

def config = grailsApplication.config.grails.paypal

static allowedMethods = [buy: 'POST', notify: 'POST']
static defaultAction = 'index'
def index = {
    redirect(controller:'company', action:'index')
}

def notify = {
    log.debug "Received IPN notification from PayPal Server ${params}"
    try {
        def config = grailsApplication.config.com.risguru.plugin.ipn
        def server = config.server
        def receiver = params.email ?: config.receiver

        if (!server || !receiver) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")

        params.cmd = "_notify-validate"
        def queryString = params.toQueryString()[1..-1]

        log.debug "Sending back query $queryString to PayPal server $server"
        def url = new URL(server)
        def conn = url.openConnection()
        conn.doOutput = true
        def writer = new OutputStreamWriter(conn.getOutputStream())
        writer.write queryString
        writer.flush()

        def result = conn.inputStream.text?.trim()

        log.debug "Got response from PayPal IPN $result"

        def purchaseOrder = orderService.getOrderByTransactionID(params.transactionId)

        if (purchaseOrder && result == 'VERIFIED') {
            if (params.receiver_email != receiver) {
                log.warn """WARNING: receiver_email parameter received from PayPal does not match configured e-mail. This request is possibly fraudulent!
                         REQUEST INFO: ${params}
                                        """
            }
            else {
                request.purchaseOrder = purchaseOrder
                def status = params.payment_status
                if (purchaseOrder.paymentStatus != PaymentStatus.COMPLETE && purchaseOrder.paymentStatus != PaymentStatus.CANCELLED) {
                    if (purchaseOrder.paypalTransactionId && purchaseOrder.paypalTransactionId == params.txn_id) {
                        log.warn """WARNING: Request tried to re-use and old PayPal transaction id. This request is possibly fraudulent!
                                REQUEST INFO: ${params} """
                    }
                    else if (status == 'Completed') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.COMPLETE
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as COMPLETE"
                    } else if (status == 'Pending') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.PENDING
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as PENDING"
                    } else if (status == 'Failed') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.FAILED
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as FAILED"
                    }
                }
            }
        }
        else {
            log.error "Error with PayPal IPN response: [$result] and Payment: [${purchaseOrder?.transactionId}]"
        }
    } catch (Exception e) {
        log.error '"**************************************************************************'
        log.error e
        log.error '"**************************************************************************'
    } finally {
        render "OK" // Paypal needs a response, otherwise it will send the notification several times!
    }
}

def success = {
    log.info "Received IPN success from PayPal Server ${params}"
    def uniqueKey = orderService.completeAndGetUniqueKeyByTransactionID(params.transactionId)
    if (!uniqueKey){
        response.sendError 403
        return
    }
    log.info "Purchase Order complete for ${params.transactionId}"
    flash.orderStatus = OrderStatus.COMPLETE
    flash.transactionId = params.transactionId
    flash.uniqueKey = uniqueKey
    if (params.returnAction || params.returnController) {
        def args = [:]
        if (params.returnAction) args.action = params.returnAction
        if (params.returnController) args.controller = params.returnController
        args.params = params
        redirect(args)
    }
    else {
        chain(action:'termOfUse')
    }
}

def cancel = {
    params?.each { key, value ->
        println "[${key}]\t=\t${value}\t::${value?.class?.name}"
    }
    log.info "Cancel Order for ${params.transactionId}"
    def status = orderService.cancelOrder(params.transactionId)
    if (!status){
        response.sendError 403
    }
    flash.orderStatus = OrderStatus.CANCEL
    flash.transactionId = params.transactionId
    if (params.cancelAction || params.cancelController) {
        def args = [:]
        if (params.cancelAction) args.action = params.cancelAction
        if (params.cancelController) args.controller = params.cancelController
        args.params = params
        redirect(args)
    }
    else {
        chain(action:'termOfUse')
    }
}

def termOfUse = {
    if (flash.orderStatus == OrderStatus.COMPLETE || flash.orderStatus == OrderStatus.CANCEL){
        return ['transactionId':flash.transactionId, 'uniqueKey':flash.uniqueKey, message:params.message]
    }

    def transactionId = params.transactionId ?: flash.transactionId
    def uniqueKey = params.uniqueKey ?: flash.uniqueKey

    def orderStatus = orderService.checkOrderStatus(transactionId)
    if (OrderStatus.COMPLETE == orderStatus){
        log.debug "Purchase Order complete for ${transactionId}"
        flash.transactionId = transactionId
        flash.orderStatus = OrderStatus.COMPLETE
        flash.uniqueKey = uniqueKey
    } else {
        def order = orderService.createOrder(uniqueKey)
        switch (order.paymentStatus) {
            case PaymentStatus.FREE:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.FREE
                break
            case PaymentStatus.INVALID:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.INVALID
                break
            case PaymentStatus.PENDING:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.CHARGE
                break
            default:
                response.sendError 403
        }
    }

    return ['transactionId':transactionId, 'uniqueKey':uniqueKey, message:params.message]
}

def buy = {
    if (params.disagree){
        return chain(action:'cancel', params:params)
    }
    def config = grailsApplication.config.com.risguru.plugin.ipn
    def server = config.server
    def receiver = params.email ?: config.receiver
    if (!server || !receiver) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")

    def order = orderService.getOrderByTransactionID(params.transactionId)
    if (!order){
        response.sendError 403
    }

    def commonParams = [transactionId: order.transactionId]

    def notifyURL = g.createLink(absolute: true, controller: 'payment', action: 'notify', params: commonParams).encodeAsURL()
    def successURL = g.createLink(absolute: true, controller: 'payment', action: 'success', params: commonParams).encodeAsURL()
    def cancelURL = g.createLink(absolute: true, controller: 'payment', action: 'cancel', params: commonParams).encodeAsURL()

    def url = new StringBuffer("$server?")
    url << "cmd=_xclick&"
    //      url << "business=${config.business}&"
    url << "business=${receiver}&"
    url << "item_name=${order.items[0].itemName}&"
    url << "item_number=${order.items[0].itemNumber}&"
    url << "quantity=${order.items[0].quantity}&"
    url << "amount=${order.items[0].unitPrice}&"
    url << "tax=${order.tax}&"
    url << "currency_code=${order.currency}&"
    if (config.test_ipn) {
        url << "test_ipn=1&"
    }
    if (config.page_style){
        url << "page_style=${config.page_style}&"
    }
    url << "notify_url=${notifyURL}&"
    url << "return=${successURL}&"
    url << "cancel_return=${cancelURL}"

    log.debug "Redirection to PayPal with URL: $url"

    redirect(url: url)
}
}

Here is the IPNcontroller I revealed from the Paypal plugin to match Paypal IPN requirement. It is in production.

package com.risguru.plugin.ipn

import com.risguru.plugin.shoppingcart.IOrderService

class PaymentController {

IOrderService orderService

def config = grailsApplication.config.grails.paypal

static allowedMethods = [buy: 'POST', notify: 'POST']
static defaultAction = 'index'
def index = {
    redirect(controller:'company', action:'index')
}

def notify = {
    log.debug "Received IPN notification from PayPal Server ${params}"
    try {
        def config = grailsApplication.config.com.risguru.plugin.ipn
        def server = config.server
        def receiver = params.email ?: config.receiver

        if (!server || !receiver) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")

        params.cmd = "_notify-validate"
        def queryString = params.toQueryString()[1..-1]

        log.debug "Sending back query $queryString to PayPal server $server"
        def url = new URL(server)
        def conn = url.openConnection()
        conn.doOutput = true
        def writer = new OutputStreamWriter(conn.getOutputStream())
        writer.write queryString
        writer.flush()

        def result = conn.inputStream.text?.trim()

        log.debug "Got response from PayPal IPN $result"

        def purchaseOrder = orderService.getOrderByTransactionID(params.transactionId)

        if (purchaseOrder && result == 'VERIFIED') {
            if (params.receiver_email != receiver) {
                log.warn """WARNING: receiver_email parameter received from PayPal does not match configured e-mail. This request is possibly fraudulent!
                         REQUEST INFO: ${params}
                                        """
            }
            else {
                request.purchaseOrder = purchaseOrder
                def status = params.payment_status
                if (purchaseOrder.paymentStatus != PaymentStatus.COMPLETE && purchaseOrder.paymentStatus != PaymentStatus.CANCELLED) {
                    if (purchaseOrder.paypalTransactionId && purchaseOrder.paypalTransactionId == params.txn_id) {
                        log.warn """WARNING: Request tried to re-use and old PayPal transaction id. This request is possibly fraudulent!
                                REQUEST INFO: ${params} """
                    }
                    else if (status == 'Completed') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.COMPLETE
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as COMPLETE"
                    } else if (status == 'Pending') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.PENDING
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as PENDING"
                    } else if (status == 'Failed') {
                        purchaseOrder.paypalTransactionId = params.txn_id
                        purchaseOrder.paymentStatus = PaymentStatus.FAILED
                        orderService.updateOrderStatus(purchaseOrder)
                        log.info "Verified payment ${purchaseOrder.paypalTransactionId} as FAILED"
                    }
                }
            }
        }
        else {
            log.error "Error with PayPal IPN response: [$result] and Payment: [${purchaseOrder?.transactionId}]"
        }
    } catch (Exception e) {
        log.error '"**************************************************************************'
        log.error e
        log.error '"**************************************************************************'
    } finally {
        render "OK" // Paypal needs a response, otherwise it will send the notification several times!
    }
}

def success = {
    log.info "Received IPN success from PayPal Server ${params}"
    def uniqueKey = orderService.completeAndGetUniqueKeyByTransactionID(params.transactionId)
    if (!uniqueKey){
        response.sendError 403
        return
    }
    log.info "Purchase Order complete for ${params.transactionId}"
    flash.orderStatus = OrderStatus.COMPLETE
    flash.transactionId = params.transactionId
    flash.uniqueKey = uniqueKey
    if (params.returnAction || params.returnController) {
        def args = [:]
        if (params.returnAction) args.action = params.returnAction
        if (params.returnController) args.controller = params.returnController
        args.params = params
        redirect(args)
    }
    else {
        chain(action:'termOfUse')
    }
}

def cancel = {
    params?.each { key, value ->
        println "[${key}]\t=\t${value}\t::${value?.class?.name}"
    }
    log.info "Cancel Order for ${params.transactionId}"
    def status = orderService.cancelOrder(params.transactionId)
    if (!status){
        response.sendError 403
    }
    flash.orderStatus = OrderStatus.CANCEL
    flash.transactionId = params.transactionId
    if (params.cancelAction || params.cancelController) {
        def args = [:]
        if (params.cancelAction) args.action = params.cancelAction
        if (params.cancelController) args.controller = params.cancelController
        args.params = params
        redirect(args)
    }
    else {
        chain(action:'termOfUse')
    }
}

def termOfUse = {
    if (flash.orderStatus == OrderStatus.COMPLETE || flash.orderStatus == OrderStatus.CANCEL){
        return ['transactionId':flash.transactionId, 'uniqueKey':flash.uniqueKey, message:params.message]
    }

    def transactionId = params.transactionId ?: flash.transactionId
    def uniqueKey = params.uniqueKey ?: flash.uniqueKey

    def orderStatus = orderService.checkOrderStatus(transactionId)
    if (OrderStatus.COMPLETE == orderStatus){
        log.debug "Purchase Order complete for ${transactionId}"
        flash.transactionId = transactionId
        flash.orderStatus = OrderStatus.COMPLETE
        flash.uniqueKey = uniqueKey
    } else {
        def order = orderService.createOrder(uniqueKey)
        switch (order.paymentStatus) {
            case PaymentStatus.FREE:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.FREE
                break
            case PaymentStatus.INVALID:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.INVALID
                break
            case PaymentStatus.PENDING:
                flash.transactionId = order.transactionId
                flash.uniqueKey = uniqueKey
                flash.orderStatus = OrderStatus.CHARGE
                break
            default:
                response.sendError 403
        }
    }

    return ['transactionId':transactionId, 'uniqueKey':uniqueKey, message:params.message]
}

def buy = {
    if (params.disagree){
        return chain(action:'cancel', params:params)
    }
    def config = grailsApplication.config.com.risguru.plugin.ipn
    def server = config.server
    def receiver = params.email ?: config.receiver
    if (!server || !receiver) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")

    def order = orderService.getOrderByTransactionID(params.transactionId)
    if (!order){
        response.sendError 403
    }

    def commonParams = [transactionId: order.transactionId]

    def notifyURL = g.createLink(absolute: true, controller: 'payment', action: 'notify', params: commonParams).encodeAsURL()
    def successURL = g.createLink(absolute: true, controller: 'payment', action: 'success', params: commonParams).encodeAsURL()
    def cancelURL = g.createLink(absolute: true, controller: 'payment', action: 'cancel', params: commonParams).encodeAsURL()

    def url = new StringBuffer("$server?")
    url << "cmd=_xclick&"
    //      url << "business=${config.business}&"
    url << "business=${receiver}&"
    url << "item_name=${order.items[0].itemName}&"
    url << "item_number=${order.items[0].itemNumber}&"
    url << "quantity=${order.items[0].quantity}&"
    url << "amount=${order.items[0].unitPrice}&"
    url << "tax=${order.tax}&"
    url << "currency_code=${order.currency}&"
    if (config.test_ipn) {
        url << "test_ipn=1&"
    }
    if (config.page_style){
        url << "page_style=${config.page_style}&"
    }
    url << "notify_url=${notifyURL}&"
    url << "return=${successURL}&"
    url << "cancel_return=${cancelURL}"

    log.debug "Redirection to PayPal with URL: $url"

    redirect(url: url)
}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文