WinRun4J 创建服务端,并注册为window服务-教程。

先创建服务端的APP


1.官网下载Winrun4j。 http://winrun4j.sourceforge.net/

2.打开winrun4j文件夹。




打开bin目录;




3.把服务端那个APP所需要的东西都复制到一块


我们看下posapp.ini里边配置:



到这一步,就差不多了,可以跑跑这个EXE,看看能不能跑起来,如果跑不起来,去看日志哪里有错误,修改哪里









接下来再创建服务端APP注册为windows服务的小玩意


我们来看下service.ini文件中的内容。

1.我们看下service.ini的配置,和APP的配置是不一样的。



2.那么重点来了,这一步才是注册为服务至关重要的一步,



文件夹里是这几个bat命令:


3.如果想把该程序注册为服务,那么以管理员身份运行这里的命令,而不是去双击运行service.exe,那样是不对的

我们下面看下这几个文件的内容,从上到下的四个:

RegisterService32.bat--


StartService32.bat--


StopService32.bat--


UnregisterService32.bat--




然后以管理员身份,去执行RegisterService32.bat这个bat,该程序就被注册为Windows服务了,去控制面板看下服务是否启动,欧克啦








下面为代码,

注意注册为服务的,需要在项目中继承  【winrun4j的AbstractService这个类】

我们可以看下这三个类的代码:

APPServer类

package hyi.pos.appserver.server

import com.google.gson.Gson

import com.google.gson.GsonBuilder

import com.google.gson.reflect.TypeToken

import com.j256.ormlite.dao.Dao

import com.j256.ormlite.dao.DaoManager

import com.j256.ormlite.dao.GenericRawResults

import com.j256.ormlite.jdbc.JdbcDatabaseConnection

import com.j256.ormlite.stmt.DeleteBuilder

import com.j256.ormlite.stmt.UpdateBuilder

import com.j256.ormlite.support.ConnectionSource

import com.j256.ormlite.support.DatabaseConnection

import com.j256.ormlite.table.TableUtils

import groovy.sql.Sql

import groovy.util.logging.Log4j

import hyi.pos.appclient.client.AppClient

import hyi.pos.appserver.server.ext.NoticeProcess

import hyi.pos.appserver.util.MposMasterCopy

import hyi.pos.db.DBUtil

import hyi.pos.entity.mpos.ApplyPlan

import hyi.pos.entity.mpos.MemberBase

import hyi.pos.entity.mpos.MemberCard

import hyi.pos.entity.mpos.Model注册

import hyi.pos.entity.mpos.MposCardDtl

import hyi.pos.entity.mpos.MposCashier

import hyi.pos.entity.mpos.MposDiffSalesOrder

import hyi.pos.entity.mpos.MposDiningArea

import hyi.pos.entity.mpos.MposDiningTable

import hyi.pos.entity.mpos.MposItemSet

import hyi.pos.entity.mpos.MposJshopTranflow

import hyi.pos.entity.mpos.MposJshopTranpay

import hyi.pos.entity.mpos.MposJshopTransaction

import hyi.pos.entity.mpos.MposLineItem

import hyi.pos.entity.mpos.MposO2oPayDtl

import hyi.pos.entity.mpos.MposSalesOrder

import hyi.pos.entity.mpos.MposServerCommand

import hyi.pos.entity.mpos.MposShift

import hyi.pos.entity.mpos.MposShiftReport

import hyi.pos.entity.mpos.MposTakeOutTranflow

import hyi.pos.entity.mpos.MposTakeOutTransaction

import hyi.pos.entity.mpos.MposTicketDtl

import hyi.pos.entity.mpos.MposTransactionTender

import hyi.pos.entity.mpos.MposTrantaste

import hyi.pos.entity.mpos.PointExItem

import hyi.pos.entity.mpos.Ticket

import hyi.pos.entity.mpos.Voucher

import hyi.pos.pay.PayUtil

import hyi.pos.pay.einvoice.EInvoiceUtil

import hyi.pos.pay.member.MemberDao

import hyi.pos.pay.member.MemberUtil

import hyi.pos.print.PrintServer

import hyi.pos.entity.mpos.MposTransaction

import org.apache.log4j.PropertyConfigurator

import java.lang.reflect.Type

import java.sql.ResultSet

import java.sql.Types

import java.text.SimpleDateFormat

import java.util.concurrent.Executors

import java.util.concurrent.TimeUnit

import java.util.concurrent.locks.Lock

import java.util.concurrent.locks.ReentrantLock

/**

* App Server for mobile POS app.

*

* Start up command:

* java -jar app_server.jar

*

* To Peeping Tom: Don't mess up my code :)

*

* @author Bruce You

* @since 2012/12/12

*/

@Log4j

class AppServer{

    static final def VERSION= '1.5.6'

    static int APP_SERVER_PORT= 3160

    static final def COLUMN_VALUE_SEPARATOR= '¦' // Pipe, Broken vertical bar

    static PushServer pushServer

static ServerSocket server

static String transDirInConf

static String dbType

static String TABLE_PREFIX

static String serverType

/** Directory where device will upload its files that are going to get processed. */

    static String uploadDir

static def dbConf

static Lock lock= new ReentrantLock()

    static masterVersion= ""

    /**

* Dining table state transition rules in STL (State Transition Language).

* Example:

*


* stl = '0空桌 -> 1点餐中 <-> 2已点餐 <-> 3结账中 -> 4已结账 & 清桌中 -> 0空桌'

*

*

* The stlMap will be:

*


* [0:1, 1:2, 2:13, 3:24, 4:0]

*

* The key is the source state, the value is the states to which could be transferred.

*/

    static stlMap= [:]

    /**

* Create server socket and listen on port 3160.

*/

    static void serverLoop() {

        dbConf= new ConfigSlurper().parse(new File('conf/db.properties').toURI().toURL())

        server= new ServerSocket(APP_SERVER_PORT)

        log.info"App server starts up (Ver ${VERSION} port=${APP_SERVER_PORT})..."

        println"App server starts up (Ver ${VERSION} port=${APP_SERVER_PORT})..."

        getUploadDir2()

        for (; ;) {

            server.accept{ Socket socket ->

try {

                    socket.setSoTimeout(dbConf.readTimeOut ?:67000)

                    protocolLoop(socket)

                } catch (Throwable e) {

                    log.warn'serverLoop> Server failed', e

}

}

}

}

    static Gson createGson() {

        new GsonBuilder().setDateFormat('yyyy-MM-dd HH:mm:ss.SSS').create()

    }

    //static String readUtf8Line(InputStream inputStream) {

//    new BufferedReader(new InputStreamReader(inputStream, "UTF-8")).readLine()

//}

    static String readLine(InputStream inputStream) throws IOException{

        //StringBuilder line = new StringBuilder(40);

        def byteBuffer= new ByteArrayOutputStream()

        boolean foundTerminator= false;

while (true) {

            int nextByte= inputStream.read();

switch (nextByte) {

                case -1:

//if (line.length() == 0 && !foundTerminator) {

                    if (byteBuffer.size() == 0 && !foundTerminator) {

                        return null;

}

                    //return line.toString();

                    return byteBuffer.toString('UTF-8')

                case /*(byte) '\r'*/ 0x0d:

if (foundTerminator) {

                        ((PushbackInputStream) inputStream).unread(nextByte);

//return line.toString();

                        return byteBuffer.toString('UTF-8')

                    }

                    foundTerminator= true;

/* Have to be able to peek ahead one byte */

                    if (!(inputStream.getClass() == PushbackInputStream.class)) {

                        inputStream= new PushbackInputStream(inputStream);

}

                    break;

case /*(byte) '\n' */ 0x0a:

//return line.toString();

                    return byteBuffer.toString('UTF-8')

                default:

if (foundTerminator) {

                        ((PushbackInputStream) inputStream).unread(nextByte);

//return line.toString();

                        return byteBuffer.toString('UTF-8')

                    }

                    //line.append((char) nextByte);

                    byteBuffer.write(nextByte)

            }

}

}

    /**

* Server-side protocol handler dispatcher.

*/

    static void protocolLoop(Socket socket) {

        log.info"Device connect: ${socket.remoteSocketAddress}"

        socket.withStreams{ InputStream input, OutputStream output ->

def command

//def deviceId = ''

            def storeIdAndDeviceId= ''

            while ((command= readLine(input)) != null) {

                try {

                    storeIdAndDeviceId= processCommand(socket, input, output, command)

                } catch (Exception e) {

                    log.error("AppServer", e)

                } finally {

                    // in case of unwritten data exists

                    output.flush()

                }

}

            log.info"[${storeIdAndDeviceId}]Device disconnect: ${socket.remoteSocketAddress}"

        }

}

    static String processCommand(socket, input, output, command) {

        PrintWriter out= new PrintWriter(socket.getOutputStream());

//BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        log.info"Server received: $command"

        System.out.println"Server received: $command"

        if (command.startsWith('ok'))

            return ''

        /*// Command format: {command} {store_id}_{device_id} [arguments...]

if (command.startsWith('ruok')) {

//心跳

output << 'ok\n'

return ''

}*/

        if (command.startsWith('generateMaster')) {//主档制作

            def args= command.split(/\s/)

            def s= ''

            if (args.size() > 1) {

                s= args[1]

            }

            log.info"Response: ok"

            MposMasterCopy.main(s== '' ?null : s)

            if (MposMasterCopy.ok) {

                log.info"MposMasterCopy: ok"

                output<< 'ok\n'

            } else {

                log.info"MposMasterCopy: ng"

                output<< 'ng\n'

            }

            return '' // finish this session immediately

        }

        def args= command.split(/\s/)

        /*if (args.length < 2)

return ''*/

        def storeIdAndDeviceId= args[1]

        def storeIdAndDeviceIdArray= storeIdAndDeviceId.split(/_/)

        if (storeIdAndDeviceIdArray.length< 2) {

            log.error("Cannot process command: \"${command}\", store_id or device_id is missed.")

            return ''

        }

        def storeId= storeIdAndDeviceIdArray[0]

        //deviceId在pos server上是机号,在后台server上是客户编号

        def deviceId= storeIdAndDeviceIdArray[1]

        //会员和支付时是pos直连后台server,需要客户编号

        def custId= storeIdAndDeviceIdArray.length> 2 ? storeIdAndDeviceIdArray[2] :''

        switch (command) {

            case ~/DownLoad\s.*/:

def tableName= args[2];

if (tableName.equals('end')) {

                    out.println('end');

out.flush();

break;

} else {

                    File file= dumpTable storeId, deviceId, tableName

FileInputStream fis= new FileInputStream(file);

File files= new File("D:\\JAVA\\TabletPos\\mobilepos\\appclient\\tmp")

                    FileOutputStream fos= new FileOutputStream(new File(files));

byte[] buffer= new byte[4096];

int c= 0;

while ((c= fis.read(buffer)) != -1) {

                        for (int i= 0; i< c; i++)

                            fos.write(buffer[i]);

System.out.println(c);

}

                    fos.close();

fis.close();

out.println(files.absolutePath);

out.flush();

break;

}

            case ~/getTable\s.*/:

def tableName= args[2]

                if (args.size() > 2) {

                    def columnName= args[3]

                    def keyName= args.size() > 4 ? args[4] :""

                    doGetTable storeId, deviceId, columnName, tableName, keyName, output, input

} else

                    doGetTable storeId, deviceId, tableName, output, input

break

            case ~/getFile\s.*/:

//TODO: 根據店号决定如何找到这个文件

                if (args.size() < 3) {

                    doGetFile2 storeId, deviceId, output, input

} else {

                    def getFile= args[2] as File

doGetFile storeId, deviceId, getFile, output, input

}

                break

            case ~/putFile\s.*/:

//TODO: 根據店号决定这个文件的路径

                def putFile= args[2] as File

doPutFile storeId, deviceId, putFile, output, input

break

            case ~/putObject\s.*/:

def objectClassName= args[2]

                def objectClass=

                        objectClassName.endsWith('.MposDiningTable') ? MposDiningTable :

objectClassName.endsWith('.MposSalesOrder') ? MposSalesOrder :

objectClassName.endsWith('.MposItemSet') ? MposItemSet :

objectClassName.endsWith('.MposTransaction') ? MposTransaction :

objectClassName.endsWith('.MposShift') ? MposShift :

objectClassName.endsWith('.MposShiftReport') ? MposShiftReport :

objectClassName.endsWith('.MposServerCommand') ? MposServerCommand :

//objectClassName.endsWith('.Pos_shift') ? Pos_shift :

//objectClassName.endsWith('.Pos_tranflow') ? Pos_tranflow :

//objectClassName.endsWith('.Pos_tranhead') ? Pos_tranhead :

//objectClassName.endsWith('.Pos_tranpay') ? Pos_tranpay :

//objectClassName.endsWith('.Tc_Shift') ? Tc_Shift :

                        (objectClassNameas Class)

                def numOfObjects= args[3].toInteger()

                doPutObject storeId, deviceId, objectClass, numOfObjects, output, input

break

            case ~/putFile2\s.*/:

putFile2 storeId, deviceId, output, input

break

        //case ~/deleteObject\s.*/:

//    def objectClassName = args[2]

//    def objectClass =

//        objectClassName.endsWith('.MposDiningTable') ? MposDiningTable :

//        objectClassName.endsWith('.MposSalesOrder') ? MposSalesOrder :

//        (objectClassName as Class)

//    def numOfObjects = args[3].toInteger()

//    doDeleteObject storeId, deviceId, objectClass, numOfObjects, output, input

//    break

            case ~/putObject2\s.*/:

doPutObject2 storeId, deviceId, args[2], args[3], args[4], output, input

break

            case ~/uploadLog\s.*/:

doUpLog storeId,deviceId,output,input

break

            case ~/getObject\s.*/:

def objectClassName= args[2]

                def objectClass=

                        objectClassName.endsWith('.MposDiningArea') ? MposDiningArea :

objectClassName.endsWith('.MposSalesOrder') ? MposSalesOrder :

objectClassName.endsWith('.MposTransaction') ? MposTransaction :

objectClassName.endsWith('.MposShiftReport') ? MposShiftReport :

(objectClassNameas Class)

                def argument=

                        objectClass== MposSalesOrder ? args[3] :// 如果要查詢点单数据,client端会带上桌子id

                                objectClass== MposTransaction ? args[3] :// 如果要查詢历史交易,client端会带上桌子代号

                                        objectClass== MposShiftReport ? args[3] :// 如果要查詢交班报表,client端会带上日期

                                                null

                doGetObject storeId, deviceId, objectClass, argument, output, input

break

            case ~/getPosVersion\s.*/:

doGetPosVersion storeId, deviceId, output, input

break

            case ~/getApkVersion\s.*/:

doGetApkVersion storeId, deviceId, output, input

break

            case ~/ruok\s.*/:

String masterVersion= ""

                try {

                    String masterJosnData= ([serverType== 'HQ' ?"db/${custId}/${storeId}/master.json" :"db/master.json"] as File).text

masterVersion= masterJosnData.split("\n")[2].split("\":\"")[1].substring(0,19)//本地master版本

                } catch (Exception e) {}

                output<< "ok_${masterVersion}\n"

                def date= null

                if (args.length> 4) {

                    date= "${args[4]} ${args[5]}"

                }

                upPosVersion custId, storeId, deviceId, args[2], args[3], date, output, input

break

            case ~/getMasterVersion\s.*/:

doGetMasterVersion storeId, deviceId, output, input

break

            case ~/checkSellOff\s.*/:

def pluno= args[2]

                checkSellOff storeId, deviceId, pluno, output, input

break

            case ~/getTransaction\s.*/:

def flowno= args[2]

                getTransaction storeId, deviceId, flowno, output, input

break

            case ~/getTransactionInfos\s.*/:

def diningTableCode= args[2]

                getTransactionInfos storeId, deviceId, diningTableCode, output, input

break

            case ~/getTransactionsAndShifts\s.*/:

def startDate= args[2]

                def endDate= args[3]

                getTransactionsAndShifts custId, storeId, deviceId, startDate, endDate, output, input

break

            case ~/getDiffSalesOrders\s.*/:

def period= args[2]

                getDiffSalesOrders deviceId, period, output, input

break

            case ~/getMposItemSets\s.*/:

def period= args[2]

                getMposItemSets storeId, deviceId, period, output, input

break

            case ~/getPlatformOrders\s.*/:

String uploadFlag= args[2]

                getPlatformOrders storeId, uploadFlag, output, input

break

            case ~/platformOrderUpdate\s.*/:

String flowno= args[2]

                String flag= args[3]

                platformOrderUpdate storeId, flowno, flag, output, input

break

            case ~/kitchenPlayUpdate\s.*/:

def id= args[2]

                kitchenPlayUpdate id, output, input

break

            case ~/putCombineTable\s.*/:

putCombineTable storeId, deviceId, output, input

break

            case ~/putSplitTable\s.*/:

putSplitTable storeId, deviceId, output, input

break

            case ~/getSalesOrders\s.*/:

def diningTableIds= args[2]

                getSalesOrders storeId, deviceId, diningTableIds, output, input

break

            case ~/o2oPay\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                def data= args[2]

                getO2oPay custId, storeId, deviceId, data, output, input

break

            case ~/getMember\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                def data= args[2]

                getMember custId, storeId, deviceId, data, output, input

break

            case ~/getMemberCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                def data= args[2]

                getMemberCard custId, storeId, deviceId, data, output, input

break

            case ~/weiXinOpenMemberCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                weiXinOpenMemberCard custId, storeId, args[2], args[3], args[4], args[5], args[6], output, input

break

            case ~/bindEntityCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }//custId, storeno, memberno, idCode, telNo, OutputStream output, InputStream input

                bindEntityCard custId, storeId, args[2], args[3], args[4], output, input

break

            case ~/registVerify\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                registVerify custId, storeId, deviceId, args[2], args[3], args.length> 4 ? args[4] :'', output, input

break

            case ~/openMemberCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                openMemberCard custId, storeId, deviceId, args[2], args[3], args[4], args[5], output, input

break

            case ~/changeMemberCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                changeMemberCard custId, storeId, deviceId, args[2], args[3], args[4], args[5], output, input

break

            case ~/updateVipPwd\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                updateVipPwd custId, storeId, deviceId, args[2], args[3], args[4], args[5], output, input

break

            case ~/updateMenberPoins\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                updateMenberPoins custId, storeId, deviceId, args[2], args[3], args[4], args[5], output, input

break

            case ~/getApplyPlan\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                getApplyPlan custId, storeId, deviceId, output, input

break

            case ~/getPointExItem\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                getPointExItem custId, storeId, deviceId, args[2], output, input

break

            case ~/apply\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                apply custId, storeId, deviceId, args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], output, input

break

            case ~/applyReturn\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                applyReturn custId, storeId, deviceId, args[2], args[3], args[4], args[5], args[6], output, input

break

            case ~/getVoucher\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                getVoucher custId, storeId, deviceId, args[2], output, input

break

            case ~/getReturnAmount\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                getReturnAmount custId, storeId, deviceId, args[2], args[3], output, input

break

            case ~/pay\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                pay custId, storeId, deviceId, args[2], args[3], args[4], output, input

break

            case ~/pay2\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                pay2 custId, storeId, deviceId, args[2], args[3], args[4], output, input

break

            case ~/integral\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                integral(custId, storeId, deviceId, output, input)

                break

            case ~/integralToMoney\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                integralToMoney(custId, storeId, deviceId, args[2], args[3], output, input)

                break

            case ~/getTicket\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                getTicket custId, storeId, deviceId, args[2], output, input

break

            case ~/loseCard\s.*/:

if (!custId) {

                    log.error("Cannot process command: \"${command}\", custId is missed.")

                    break

                }

                loseCard custId, storeId, deviceId, args[2], args[3], args[4], output, input

case ~/getAccDate\s.*/:

String accDate= getAccDate(storeId)

                log.info("${storeId} accDate = ${accDate}")

                output<< "${accDate}\n"

                break

            case ~/updateAccDate\s.*/:

updateAccdate(args[2], args[3], args[4], args[5], storeId, custId)

                break

            case ~/notice\s.*/:

(new NoticeProcess()).process(input, output, storeId, deviceId, args)

                break

            case ~/getEInvoice\s.*/:

getEInvoice(custId, storeId, deviceId, args.length> 2 ? args[2] :'', output, input)

                break

            case ~/checkObject\s.*/:

def objectClassName= args[2]

                def objectClass=

                        objectClassName.endsWith('.MposDiningTable') ? MposDiningTable :

(objectClassNameas Class)

                doCheckObject storeId, deviceId, objectClass, output, input

break

            case ~/updateMemberMemo4\s.*/:

updateMemberMemo4 custId, storeId, deviceId, args[2], args[3], output, input

break

            default:

output<< "Response: ${command}\n"

        }

        return storeIdAndDeviceId

}

static  void doUpLog(storeId,deviceId,OutputStream output,InputStream input) {

    DataInputStream dataInputStream= new DataInputStream(input);

File file= new File("log\\" + storeId+ "-" + deviceId);

/* if (!file.exists()){

file.mkdir();

}*/

    FileOutputStream fileOutputStream1= new FileOutputStream(file);

byte[] bytes= new byte[51200];

int length= 0;

while ((length= dataInputStream.read(bytes)) != -1) {

        fileOutputStream1.write(bytes,0,length);

fileOutputStream1.flush();

}

    fileOutputStream1.close();

dataInputStream.close();

}

    static void doCheckObject(storeId, deviceId, objectClass, OutputStream output, InputStream input) {

        log.info"[${storeId}_${deviceId}]Going to get ${objectClass.toString()}objects"

        String objectsInJSON= readLine(input)

        log.info"[${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        def gson= createGson()

        if (objectClass== MposDiningTable) { // 桌子状态更新上传

            Type collectionType= new TypeToken>(){}.getType()

            List diningTables= gson.fromJson(objectsInJSON, collectionType)

            def connSrc= getDbConnection(false)

            def dao= DaoManager.createDao(connSrc, MposDiningTable)

            def errResponse= checkDiningTableState(dao, diningTables)

            if (errResponse) {

                output<< errResponse+ "\n"

                log.info"[${storeId}_${deviceId}]Send: $errResponse"

                return

            }

}

        output<< 'ok\n'

        log.info"[${storeId}_${deviceId}]Send: ok"

    }

    //下单时检查桌子是否是空桌

    static String checkDiningTableState(Dao dao, List diningTables) {

        for (diningTablein diningTables) {

            def origDiningTable= dao.queryForId(diningTable.fId)

            def sourceState= origDiningTable.state

def targetState= diningTable.state

if (sourceState!= targetState) {

                // reject the transition

                def response= "ng Reject the dinging table state from $sourceState to $targetState"

                return response

}

}

        return null

    }

    //更新营业日期

    static void updateAccdate(accdate, shiftNumber, begFlowNo, endFlowNo, storeId, custId) {

        log.info("updateAccdate ${accdate} ${shiftNumber} ${begFlowNo} ${endFlowNo} ${storeId}")

        def transDb= getDbConnection(false)

        def tdao= DaoManager.createDao(transDb, MposTicketDtl)

        tdao.callBatchTasks{

            UpdateBuilder tupdateBuilder= tdao.updateBuilder()

            tupdateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('WarehouseID', storeId).and().between('Flowno', begFlowNo, endFlowNo)

            tupdateBuilder.update()

            def odao= DaoManager.createDao(transDb, MposO2oPayDtl)

            UpdateBuilder oupdateBuilder= odao.updateBuilder()

            oupdateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('Warehouseid', storeId).and().between('Flowno', begFlowNo, endFlowNo)

            oupdateBuilder.update()

            def cdao= DaoManager.createDao(transDb, MposCardDtl)

            UpdateBuilder cupdateBuilder= cdao.updateBuilder()

            cupdateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('Warehouseid', storeId).and().between('Flowno', begFlowNo, endFlowNo)

            cupdateBuilder.update()

            def ldao= DaoManager.createDao(transDb, MposLineItem)

            UpdateBuilder iupdateBuilder= ldao.updateBuilder()

            iupdateBuilder.updateColumnValue('AccDate', accdate).where().eq('custId', custId).and().eq('WarehouseID', storeId).and().between('flowno', begFlowNo, endFlowNo)

            iupdateBuilder.update()

            def ttdao= DaoManager.createDao(transDb, MposTransactionTender)

            UpdateBuilder ttupdateBuilder= ttdao.updateBuilder()

            ttupdateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('WarehouseID', storeId).and().between('flowno', begFlowNo, endFlowNo)

            ttupdateBuilder.update()

            def tsdao= DaoManager.createDao(transDb, MposTransaction)

            UpdateBuilder tstupdateBuilder= tsdao.updateBuilder()

            tstupdateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('Warehouseid', storeId).and().between('Flowno', begFlowNo, endFlowNo)

            tstupdateBuilder.update()

            def dao= DaoManager.createDao(transDb, MposShiftReport)

            UpdateBuilder updateBuilder= dao.updateBuilder()

            updateBuilder.updateColumnValue('Accdate', accdate).where().eq('custId', custId).and().eq('warehouseId', storeId).and().eq('flowno', shiftNumber)

            updateBuilder.update()

            def sao= DaoManager.createDao(transDb, MposShift)

            UpdateBuilder supdateBuilder= sao.updateBuilder()

            supdateBuilder.updateColumnValue('fAccDate',new SimpleDateFormat('yyyy-MM-dd').parse(accdate)).where().eq('custId', custId).and().eq('warehouseId', storeId).and().eq('fShift', shiftNumber)

            supdateBuilder.update()

        }

}

    /**

* 挂失/解挂

*  接收

*  idCode 卡识别号

*  type 状态(1:挂失,2:解挂)

*  返回

*  ok 挂失/解挂成功

*  ng 挂失/解挂失败

*/

    static void loseCard(custId, storeId, deviceId, idCode, type, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]Going to get loseCard of ${idCode} ${type}"

        def connSrc= getDbConnection()

        String result= MemberUtil.loseCard(custId, idCode, type, cashierNumber, connSrc)

        output<< "${result}"

    }

    /**

* 通过礼劵编号查询

*  接收

*  code 礼劵编号

*

*  返回

*  Ticket对象, Ticket对象包含TicketBatch

*/

    static void getTicket(custId, storeId, deviceId, code, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]Going to get getTicket of ${code}"

        def connSrc= getDbConnection()

        Ticket ticket= MemberDao.queryTicketByCode(custId, code, connSrc)

        def gson= createGson()

        def json= gson.toJson(ticket)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${Ticket.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    /**

* 礼券消费扣款

*  接收

*  code 礼券编号

*  amount 扣款金额,礼券允许多次使用时填要扣的金额,如果是一次性则填0

*  cashierNumber 操作员

*  transactions 交易数据

*

*  返回

*  ok_XX 扣款成功,XX表示扣款金额,允许溢收

*  ng 扣款失败,数据插入失败

*  noUse 扣款失败,不满足扣款条件

*  Ticket 礼券不存在

*  status_8 礼券已注销

*

*/

    static void pay2(custId, storeId, deviceId, code, amount, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] pay2 ${code}"

        String objectsInJSON= readLine(input)

        log.info"[${custId}_${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List transactions= gson.fromJson(objectsInJSON, collectionType)

        if (transactions) {

            def connSrc= getDbConnection()

            String result= MemberUtil.pay2(custId, storeId, code, amountas BigDecimal, transactions.get(0), cashierNumber, connSrc)

            output<< "${result}"

        } else {

            output<< 'ng\n'

        }

}

    /**

* 会员储值卡消费扣款

*  接收

*  idCode 卡识别卡号

*  amount 扣款金额,退金额填负数

*  cashierNumber 操作员

*  transactions 交易数据

*

*  返回

*  ok 扣款成功

*  ng 扣款失败,数据插入失败

*  Member 扣款失败,找不到会员卡/会员钱包/钱包使用规则

*  noUse 扣款失败,不满足扣款条件

*  noBalance 余额不足

*/

    static void pay(custId, storeId, deviceId, idCode, amount, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] pay ${idCode} ${amount} "

        String objectsInJSON= readLine(input)

        log.info"[${custId}_${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List transactions= gson.fromJson(objectsInJSON, collectionType)

        if (transactions) {

            def connSrc= getDbConnection()

            String result= MemberUtil.pay(custId, storeId, idCode, amountas BigDecimal, transactions.get(0), cashierNumber, connSrc)

            output<< "${result}"

        } else {

            output<< 'ng\n'

        }

}

    /**

* 计算积分

*

*  返回

*  本次积分或0(0积分或计算积分失败)

*/

    static void integral(custId, storeId, deviceId, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] integral "

        String objectsInJSON= readLine(input)

        log.info"[${custId}_${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List transactions= gson.fromJson(objectsInJSON, collectionType)

        if (transactions) {

            def connSrc= getDbConnection()

            String result= MemberUtil.integral(custId, storeId, transactions.get(0), connSrc)

            output<< "${result}"

        } else {

            output<< '0\n'

        }

}

    /**

* 积分抵扣

*  接收

*  vipNo 会员号或手机号

*  inputMoney 输入的抵扣金额

*  transactions 交易数据

*

*  返回

*  ok 支付成功

*  ng 支付失败ø

*  noIntegral 积分不足

*/

    static void integralToMoney(custId, storeId, deviceId, vipNo, inputMoney, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] integralToMoney "

        String objectsInJSON= readLine(input)

        log.info"[${custId}_${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List transactions= gson.fromJson(objectsInJSON, collectionType)

        if (transactions) {

            def connSrc= getDbConnection()

            String result= MemberUtil.integralToMoney(custId, storeId, vipNo, inputMoney, transactions.get(0), connSrc)

            output<< "${result}"

        } else {

            output<< 'ng\n'

        }

}

    /**

* 获取会员可退金额

*  接收

*  idCode 卡识别卡号

*  eWalletType 钱包类型

*

*  返回

*  ok_XX 获取可退金额成功,XX表示可退金额

*  ng 获取可退金额失败,数据插入失败

*

*/

    static void getReturnAmount(custId, storeId, deviceId, idCode, eWalletType, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] getReturnAmount ${idCode} ${eWalletType}"

        def connSrc= getDbConnection()

        String result= MemberUtil.getReturnAmount(custId, idCode, eWalletType, connSrc)

        output<< "${result}"

    }

    /**

* 通过交易号查询会员充值凭证

*  接收

*  flowNo 交易号

*

*  返回

*  Voucher对象, Voucher对象中包含List

*/

    static void getVoucher(custId, storeId, deviceId, flowNo, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]Going to get getVoucher of ${flowNo}"

        def connSrc= getDbConnection()

        Voucher voucher= MemberDao.queryVoucherByFlowNo(custId, storeId, flowNo, connSrc)

        def gson= createGson()

        def json= gson.toJson(voucher)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${Voucher.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    /**

* 会员充值/充值退款

*  接收

*  idCode 卡识别卡号

*  eWalletType 钱包类型

*  planNo 充值方案编号,如果是手输金额或退款,则填0即可

*  payment 支付代号:支付金额金额,多种支付方式用英文逗号隔开,例如【A:100,B:100】 退款时金额加负号

*  amount 充值总金额/充值总次数  退款时金额加负号

*  unitPrice 计次钱包充值时,带上单价,其它情况填0即可

*  flowNo pos交易序号

*

*  返回

*  ok_XX 充值成功,XX表示充值凭证编号

*  ng 充值失败,数据插入失败

*  Member 充值失败,找不到会员卡/会员钱包/钱包使用规则

*  charge 充值失败,钱包不允许充值

*  cardStatus_XX 充值失败,会员卡或会员钱包不可用, XX表示卡或钱包状态

*/

    static void apply(custId, storeId, deviceId, idCode, eWalletType, planNo, payment, amount, unitPrice, cashierNumber, flowNo, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] apply ${idCode} ${eWalletType} ${planNo} ${amount} ${unitPrice} ${flowNo}"

        def connSrc= getDbConnection()

        String result= MemberUtil.apply(custId, storeId, deviceId, idCode, eWalletType, planNo, payment, amount, unitPrice, cashierNumber, flowNo, connSrc)

        output<< "${result}\n"

    }

    /**

* 会员充值退货

*  接收

*  payment 支付代号:支付金额金额,多种支付方式用英文逗号隔开,例如【A:100,B:100】 退款时金额加负号

*  amount 充值总金额/充值总次数  退款时金额加负号

*  flowno 充值退货的交易号

*  rtnFlowno 原充值交易号

*  返回

*  ok_XX 充值退货成功,XX表示充值凭证编号

*  ng 充值退货失败,数据插入失败

*  Member 充值退货失败,找不到会员卡/会员钱包/钱包使用规则

*  Balance 充值退货失败,钱包余额不够

*/

    static void applyReturn(custId, storeId, deviceId, payment, amount, cashierNumber, flowno, rtnFlowno, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] applyReturn ${payment}  ${amount} ${flowno} ${rtnFlowno}"

        def connSrc= getDbConnection()

        String result= MemberUtil.applyReturn(custId, storeId, deviceId, payment, amount,  cashierNumber,flowno, rtnFlowno, connSrc)

        output<< "${result}\n"

    }

    /**

* 获取会员充值方案

*

*  返回

*  List

*/

    static void getApplyPlan(custId, storeId, deviceId, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}] getApplyPlan"

        def connSrc= getDbConnection()

        List applyPlanList= MemberDao.queryApplyPlan(custId, storeId, connSrc)

        def gson= createGson()

        def json= gson.toJson(applyPlanList)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${MemberCard.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    /**

* 获取积分兑换方案

*

*  返回

*  List

*/

    static void getPointExItem(custId, storeId, deviceId, point, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId} ${point}] getApplyPlan"

        def connSrc= getDbConnection()

        List pointExItem= MemberDao.queryPointExItem(Integer.valueOf(point), connSrc)

        def gson= createGson()

        def json= gson.toJson(pointExItem)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${MemberCard.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    /**

* 会员换卡

*  接收

*  oldIdCode 旧卡识别卡号

*  idCode  新卡识别卡号

*

*  返回

*  ok 换卡成功

*  password 换卡失败,密码错误

*  ng 换卡失败,数据插入失败

*  OldMemberCard 换卡失败,旧卡不存在

*  cardStatus_XX 换卡失败,新会员卡已经存在, XX表示卡状态

*/

    static void changeMemberCard(custId, storeId, deviceId, oldIdCode, idCode, password, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]changeMemberCard ${oldIdCode} ${idCode} ${cashierNumber}"

        def connSrc= getDbConnection()

        //换卡

        int result= MemberUtil.changeMemberCard(custId, storeId, oldIdCode, idCode, password, cashierNumber, connSrc)

        if (result== 0) {

            log.info"[${custId}_${storeId}_${deviceId}] changeMemberCard ok."

            output<< 'ok\n'

        } else if (result== -1) {

            log.info"[${custId}_${storeId}_${deviceId}] changeMemberCard ng."

            output<< 'ng\n'

        } else if (result== -2) {

            log.info"[${custId}_${storeId}_${deviceId}] changeMemberCard password error."

            output<< 'password\n'

        } else if (result== 1) {

            log.info"[${custId}_${storeId}_${deviceId}] changeMemberCard old MemberCard null."

            output<< 'OldMemberCard\n'

        } else {

            int cardStatus= result- 2

            log.info"[${custId}_${storeId}_${deviceId}] changeMemberCard new memberCard.cardStatus = ${cardStatus}."

            output<< "cardStatus_${result}\n"

        }

}

    /**

* 修改会员密码

*  接收

*  oldIdCode 旧卡识别卡号

*  newPwd  新密码

*

*  返回

*  ok 修改成功

*  password 修改失败,密码错误

*  ng 修改失败,数据插入失败

*  OldMemberCard 修改失败,卡号不存在

*/

    static void updateVipPwd(custId, storeId, deviceId, oldIdCode, newPwd, password, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]updateVipPwd ${oldIdCode} ${newPwd} ${cashierNumber}"

        def connSrc= getDbConnection()

        //修改会员密码

        int result= MemberUtil.updateVipPwd(custId, storeId, oldIdCode, newPwd, password, cashierNumber, connSrc)

        if (result== 0) {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd ok."

            output<< 'ok\n'

        } else if (result== -1) {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd ng."

            output<< 'ng\n'

        } else if (result== -2) {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd password error."

            output<< 'password\n'

        } else {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd old updateVipPwd null."

            output<< 'OldMemberCard\n'

        }

}

    /**

* 修改会员积分

*  接收

*  oldIdCode 卡识别卡号

*

*  返回

*  ok 修改成功

*  ng 修改失败,数据插入失败

*/

    static void updateMenberPoins(custId, storeId, deviceId, point, vipNo, cashierNumber, flowNo, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]updateVipPwd ${point} ${vipNo} ${cashierNumber}"

        def connSrc= getDbConnection()

        //修改会员积分

        int result= MemberUtil.updateMenberPoins(custId, storeId, point, vipNo, cashierNumber, flowNo, connSrc)

        if (result== 0) {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd ok."

            output<< 'ok\n'

        } else {

            log.info"[${custId}_${storeId}_${deviceId}] updateVipPwd old updateVipPwd null."

            output<< 'ng\n'

        }

}

    /**

* 修改会员支付凭证

*  接收

*  memberno 会员事情

*  memo4 支付凭证

*

*  返回

*  ok 修改成功

*  ng 修改失败,数据插入失败

*

*/

    static void updateMemberMemo4(custId, storeId, deviceId, memberno, memo4, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]updateMemberMemo4 ${memberno} ${memo4} "

        def connSrc= getDbConnection()

        MemberBase memberBase= MemberDao.queryMemberByMemberNo(custId, memberno, connSrc)

        if (memberBase) {

            log.info"[${custId}_${storeId}_${deviceId}]updateMemberMemo4  memberBase"

            memberBase.memo4= memo4

if (MemberDao.updateMemberIntegral(memberBase, connSrc)) {

                output<< 'ok\n'

                return

            }

}

        output<< 'ng\n'

        return

    }

    /**

* 微信会员开卡

*  接收

*  memberno 会员ID(微信识别码)

*  idCode 微信会员卡编号

*  chipNumber 微信会员卡code

*  telNo 联系电话

*  memName 姓名

*  sex 性别

*  birthdate 生日

*

*  返回

*  ok 开卡成功

*  ng 开卡失败,数据插入失败

*  EWallet 开卡失败,后台未设置钱包规则

*  cardStatus_XX 开卡失败,会员卡已经存在, XX表示卡状态

*

*/

    static void weiXinOpenMemberCard(custId, storeno, memberno, idCode, chipNumber, telNo, memName, sex, birthdate, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeno}_${memberno}]weiXinOpenMemberCard ${idCode} ${telNo} ${memName} ${sex} ${birthdate}"

        def connSrc= getDbConnection()

        //开卡

        def isDoubleMember= dbConf.isDoubleMember ?:'1'

        int result= MemberUtil.weiXinOpenMemberCard custId, storeno, memberno, idCode, chipNumber, telNo, memName, sex, birthdate, isDoubleMember, connSrc

if (result== 0) {

            log.info"[${custId}_${storeno}_${memberno}] weiXinOpenMemberCard ok."

            output<< 'ok\n'

        } else if (result== 1) {

            log.info"[${custId}_${storeno}_${memberno}] weiXinOpenMemberCard EWallet null."

            output<< 'EWallet\n'

        } else if (result== -2) {

            log.info"[${custId}_${storeno}_${memberno}] weiXinOpenMemberCard member exist."

            output<< 'exist\n'

        } else if (result== -1) {

            log.info"[${custId}_${storeno}_${memberno}] weiXinOpenMemberCard ng."

            output<< 'ng\n'

        } else {

            int cardStatus= result- 2

            log.info"[${custId}_${storeno}_${memberno}] weiXinOpenMemberCard memberCard.cardStatus = ${cardStatus}."

            output<< "cardStatus_${result}\n"

        }

}

    /**

* 绑定实体卡

*  接收

*  idCode 微信会员卡号

*  memberno 会员号

*  custId 客户号

*  storeno 店号

*

*  返回

*  ok 绑定成功

*  ng 绑定失败

*  noMemberCard 没有找到会员卡

*  noMember 没有找到会员

*  cardStatus_XX 会员卡状态不正常, XX表示卡状态

*  memberStatus_XX 会员状态不正常, XX表示会员状态

*

*/

    static void bindEntityCard(custId, storeno, memberno, idCode, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeno}_${memberno}]bindEntityCard ${idCode}"

        def connSrc= getDbConnection()

        //绑定

        String result= MemberUtil.bindEntityCard custId, storeno, memberno, idCode, connSrc

output<< "${result}\n"

    }

    /**

* 注册验证

*  接收

*  code 。。(注册)码

*  custId 客户号

*  storeno 店号

*  deviceId 机号

*

*  返回

*  ok 验证成功

*  ng 验证失败

*

*/

    static void registVerify(custId, storeId, deviceId, code, type, layoutCode, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]registVerify ${code} ${type}"

        def connSrc= getDbConnection()

        //注册申请

        if (type== '0') {

            try {

                def tDao= DaoManager.createDao(connSrc, Model注册)

                List lists= tDao.queryBuilder().where().eq('custId', custId).and().eq('Warehouseid', storeId).and().eq('FSYSNO', deviceId).query()

                if (lists&& lists.size() > 0) {

                    Model注册 model注册= lists.get(0)

                    if (model注册) {

                        if (model注册.FSYSID== code) {

                            output<< "ok\n"

                            return

                        } else {

                            output<< "ng\n"

                            return

                        }

}

}

                lists= tDao.queryBuilder().where().eq('FSYSID', code).query()

                if (lists&& lists.size() > 0) {

                    Model注册 model注册= lists.get(0)

                    if (model注册) {

                        if (model注册.custId== custId&& model注册.Warehouseid== storeId&& model注册.FSYSNO== deviceId) {

                            output<< "ok\n"

                            return

                        } else {

                            output<< "ng\n"

                            return

                        }

}

}

                List list= tDao.queryForAll()

                int maxId= 0

                for (Model注册 model注册 : list) {

                    if (model注册.FSYSNUM> maxId) {

                        maxId= model注册.FSYSNUM

}

}

                maxId++

                Model注册 model注册= new Model注册()

                model注册.FSYSNUM= maxId

model注册.FSYSNO= deviceId

model注册.FSYSID= code

model注册.FSYSTYPE= 1

                model注册.FSYSFLAG= 0

                model注册.FMEMO= layoutCode

model注册.FPOSTYPE= layoutCode== 'ls_layout' ?1 :(layoutCode== 'coffe_table_layout' ?2 :(layoutCode== 'food_table_layout' ?3 :0))

                model注册.FOPERATOR= ''

                model注册.FUPDDATE= new Date()

                model注册.custId= custId

model注册.Warehouseid= storeId

tDao.create(model注册)

                output<< "ok\n"

            } catch (Exception e){

                log.error('registVerify failed' , e)

                output<< "ng\n"

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

}

        } else {

            //注册验证

            String result= MemberUtil.registVerify custId, storeId, deviceId, code,type, connSrc

output<< "${result}\n"

        }

}

    /**

* 会员开卡

*  接收

*  idCode 识别卡号

*  telNo 联系电话

*  cashierNumber 操作员

*  deposit 押金

*

*  返回

*  ok 开卡成功

*  ng 开卡失败,数据插入失败

*  EWallet 开卡失败,后台未设置钱包规则

*  cardStatus_XX 开卡失败,会员卡已经存在, XX表示卡状态

*

*/

    static void openMemberCard(custId, storeId, deviceId, idCode, telNo, deposit, cashierNumber, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]createMemberCard ${idCode} ${telNo} ${cashierNumber}"

        def connSrc= getDbConnection()

        //开卡

        def isDoubleMember= dbConf.isDoubleMember ?:'1'

        int result= MemberUtil.openMemberCard custId, storeId, idCode, telNo, deposit, isDoubleMember, cashierNumber, connSrc

if (result== 0) {

            log.info"[${custId}_${storeId}_${deviceId}] createMemberCard ok."

            output<< 'ok\n'

        } else if (result== 1) {

            log.info"[${custId}_${storeId}_${deviceId}] createMemberCard EWallet null."

            output<< 'EWallet\n'

        } else if (result== -2) {

            log.info"[${custId}_${storeId}_${deviceId}] createMemberCard member exist."

            output<< 'exist\n'

        } else if (result== -1) {

            log.info"[${custId}_${storeId}_${deviceId}] createMemberCard ng."

            output<< 'ng\n'

        } else {

            int cardStatus= result- 2

            log.info"[${custId}_${storeId}_${deviceId}] createMemberCard memberCard.cardStatus = ${cardStatus}."

            output<< "cardStatus_${result}\n"

        }

}

    /**

* 根据卡号查询会员卡资料

*  接收

*  idCode 卡片识别号

*

*  返回

*    MemberCard对象, MemberCard中包含List

*/

    static void getMemberCard(custId, storeId, deviceId, idCode, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]Going to get MemberCard of ${idCode}"

        def connSrc= getDbConnection()

        MemberCard memberCard= MemberDao.queryMemberCardByIdCode2(custId, idCode, connSrc)

        def gson= createGson()

        def json= gson.toJson(memberCard)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${MemberCard.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    /**

* 根据会员号或手机号查询会员资料

*  接收

*  data 会员号/手机号 三者一一对应

*

*  返回

*  MemberBase对象,MemberBase中包含List

*

*/

    static void getMember(custId, storeId, deviceId, data, OutputStream output, InputStream input) {

        log.info"[${custId}_${storeId}_${deviceId}]Going to get MemberBase of ${data}"

        def connSrc= getDbConnection()

        MemberBase memberBase= MemberDao.queryMember(storeId, custId, data, connSrc)

        def gson= createGson()

        def json= gson.toJson(memberBase)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${custId}_${storeId}_${deviceId}]Send ${MemberBase.simpleName}: ${json}"

        def response= readLine(input)

        if (response)

            log.info"[${custId}_${storeId}_${deviceId}]Client response: ${response}"

        else

            log.info"[${custId}_${storeId}_${deviceId}]Client disconnected."

    }

    static boolean doGetFile2(storeId, deviceId, OutputStream output, InputStream input) {

        def files= ("download/${deviceId}/${storeId}" as File)

        if (!files.exists()) {

            files.mkdirs()

        }

        def fs= files.listFiles()

        output<< "${fs.size()}\n"

        for (File getFile : fs) {

            log.info"[${storeId}_${deviceId}]Send file size: ${getFile.length()}"

            output<< "${getFile.length()}\n"

            log.info"[${storeId}_${deviceId}]Send file name: ${getFile.getName()}"

            output<< "${getFile.getName()}\n"

            log.info"[${storeId}_${deviceId}]Send file content: $getFile"

            def getFileInputStream= null

            try {

                getFileInputStream= new BufferedInputStream(new FileInputStream(getFile))

                copy storeId, deviceId, getFileInputStream, output

} catch (Exception e) {

                throw e

} finally {

                getFileInputStream?.close()

            }

}

        def response= readLine(input)

        if (response) {

            for (File getFile : fs) {

                log.info"[${storeId}_${deviceId}]delete file: ${getFile.getName()}"

                getFile.delete()

            }

            log.info"[${storeId}_${deviceId}]Client response: ${response}"

        } else

            log.info"[${storeId}_${deviceId}]Client disconnected."

        return true

    }

    /**

* Dump a database table.

*

* File format:

* column_name_1/column_type_1,column_name_2/column_type_2,column_name_3/column_type_3,...\n

* column_value_1,column_value_2,column_value_3,...\n

* column_value_1,column_value_2,column_value_3,...\n

* ...

*

* Field type:

* S: String, I: Integer, D: Date, F: Decimal

*/

    static File dumpTable(storeId, deviceId, String tableName) {

        Sql serverDb= getGroovySql()

        try {

            // Create temp file

            def tempFileDir= new File('tmp')

            tempFileDir.mkdir()

            def tempFile= File.createTempFile(tableName,'.sql', tempFileDir)

            tempFile.withWriter('UTF-8') { writer ->

// Table schema query

                def columnCount= 0

                def selectSql= dbType== 'MySQL' ?

"select * from ${tableName} limit 1".toString() :

"select top 1 * from ${TABLE_PREFIX}${tableName}".toString()

                def hasStoreIdColumn= false

                serverDb.query(selectSql) { ResultSet rs ->

columnCount= rs.metaData.columnCount

for (iin 1..columnCount) {

                        def columnName= rs.metaData.getColumnName(i)

                        if (columnName== 'store_id')

                            hasStoreIdColumn= true

                        writer<< columnName

writer<< '/'

                        switch (rs.metaData.getColumnType(i)) {

                            case Types.CHAR:

case Types.VARCHAR:

case Types.NCHAR:

case Types.NVARCHAR:

writer<< 'S'

                                break

                            case Types.INTEGER:

case Types.BIGINT:

case Types.SMALLINT:

writer<< 'I'

                                break

                            case Types.DATE:

case Types.TIMESTAMP:

writer<< 'D'

                                break

                            case Types.DECIMAL:

case Types.FLOAT:

case Types.DOUBLE:

writer<< 'F'

                                break

                            default:

writer<< 'S'

                        }

                        if (i< columnCount)

                            writer<< ','

                    }

                    writer<< '\n'

                }

                // Table content query

                def selectAll= "select * from ${TABLE_PREFIX}${tableName}"

                if (hasStoreIdColumn)

                    selectAll+= " where store_id=${storeId}"

                serverDb.eachRow(selectAll.toString()) { row ->

for (iin 0..

                        writer<< row[i]

                        if (i< columnCount- 1) {

                            writer<< COLUMN_VALUE_SEPARATOR

}

}

                    writer<< '\n'

                }

                log.info"[${storeId}_${deviceId}]Table dump: $tempFilewas created"

            }

            return tempFile

} catch (Exception e) {

            log.error("[${storeId}_${deviceId}]doGetTable() failed", e)

            return null

        } finally {

            serverDb?.close()

        }

}

    static void doGetTable(storeId, deviceId, String columnName, String tablename, String keyName,

OutputStream output, InputStream input) {

        log.info"[${storeId}_${deviceId}]Going to get ${tablename} ${keyName}"

        def connSrc= getDbConnection()

        def tDao= DaoManager.createDao(connSrc, MposCashier)

        String sql= "select ${columnName} from ${tablename}"

        if (keyName!= '')

            sql+= " where ${keyName} = '${storeId}'"

        GenericRawResults rawResults= tDao.queryRaw(sql)

        List results= new ArrayList();

results.add(rawResults.getColumnNames())

        results.addAll(rawResults.getResults())

        def gson= createGson()

        def json= gson.toJson(results)

        output<< json

output<< '\n'

        output.flush()

        log.info"[${storeId}_${deviceId}]Send ${tablename}: ${results.size()}"

    }

    /**

* Server-side getTable protocol handler.

*


*        Server                Client

* --------------------  --------------------

*          "getTable {store_id}_{device_id}{table_name}\n"

*          <----------------------

*            "{file_size}\n" or -1 if rejected

*          ---------------------->

*            "{file content}"

*          ---------------------->

*            "ok\n" or "ng\n"

*          <----------------------

*

*/

    static boolean doGetTable(storeId, deviceId, String tableName, OutputStream output, InputStream input) {

        File tableFile

try {

            tableFile= dumpTable(storeId, deviceId, tableName)

            doGetFile(storeId, deviceId, tableFile, output, input)

        } finally {

            tableFile?.delete()

            if (tableFile)

                log.info"[${storeId}_${deviceId}]Table dump: $tableFilewas deleted."

        }

}

    /**

* Server-side getFile protocol handler.

*


*        Server                Client

* --------------------  --------------------

*          "getFile {store_id}_{device_id}{file_name}\n"

*          <----------------------

*            "{file_size}\n" or -1 if rejected

*          ---------------------->

*            "{file content}"

*          ---------------------->

*            "ok\n" or "ng\n"

*          <----------------------

*

*/

    static boolean doGetFile(storeId, deviceId, File getFile, OutputStream output, InputStream input) {

        if (getFile.exists()) {

            log.info"[${storeId}_${deviceId}]Send file size: ${getFile.length()}"

            output<< "${getFile.length()}\n"

            log.info"[${storeId}_${deviceId}]Send file content: $getFile"

            def getFileInputStream= null

            try {

                getFileInputStream= new BufferedInputStream(new FileInputStream(getFile))

                copy storeId, deviceId, getFileInputStream, output

} catch (Exception e) {

                // rethrow the exception to interrupt the whole process

                log.error(e)

                throw e

} finally {

                getFileInputStream?.close()

            }

        } else {

            output<< '0\n'

        }

        def response= readLine(input)

        if (response) {

            if (getFile.getName().endsWith('update.zip')) {

                getFile.delete()

            }

            log.info"[${storeId}_${deviceId}]Client response: ${response}"

        } else

            log.info"[${storeId}_${deviceId}]Client disconnected."

        return true

    }

    /**

* Server-side putFile protocol handler.

*


*        Server                Client

* --------------------  --------------------

*          "putFile {store_id}_{device_id}{file_name}\n"

*          <----------------------

*            "{file_size}\n"

*          <----------------------

*            "{file content}"

*          <----------------------

*            "ok\n" or "ng\n"

*          ---------------------->

*

*

* Upload the file and save it as "trans/{file}_{store id}_{device id}_{week}.db".

*/

    static void doPutFile(storeId, deviceId, File putFile, OutputStream output, InputStream input) {

        def putFileOutputStream= null

        try {

            def fileSize= readLine(input).toInteger()

            File transDir= new File(transDirInConf)

            transDir.mkdir()

            def weekName= String.format('%1$ta', Calendar.getInstance())

            File fileUpload= new File(transDir,"${putFile.name}_${storeId}_${deviceId}_${weekName}.db")

            log.info"[${storeId}_${deviceId}]Receiving file: ${putFile.name} to ${fileUpload}, size: ${fileSize}"

            putFileOutputStream= new BufferedOutputStream(new FileOutputStream(fileUpload))

            copy storeId, deviceId, input, putFileOutputStream, fileSize

output<< 'ok\n'

            log.info"[${storeId}_${deviceId}]Send ok."

        } catch (Exception e) {

            log.warn"[${storeId}_${deviceId}]doPutFile failed", e

output<< 'ng\n'

        } finally {

            putFileOutputStream?.close()

        }

}

    /**

* Server-side doPutMasterVersion protocol handler.

*


*        Server                Client

* --------------------  --------------------

*        "doPutMasterVersion {store_id}_{device_id}\n"

*          <----------------------

*            "{json_file_size}\n"  or -1 if upload directory is not empty

*          ---------------------->

*            "{file content}"

*          ---------------------->

*            "ok\n" or "ng\n"

*          <----------------------

*

*/

    static void putFile2(storeId, deviceId, OutputStream output, InputStream input) {

        int filesize= Integer.valueOf(readLine(input))

        final ByteArrayOutputStream jsonBytes= new ByteArrayOutputStream()

        copy2(input, jsonBytes, filesize)

        final String objectsInJSON= jsonBytes.toString('UTF-8')

        jsonBytes.close()

        SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd-HH")

        Date date= new Date()

        String date2= sdf.format(date)

        if (!(['posLog'] as File).exists()) {

            (['posLog'] as File).mkdirs()

        }

        File[] files= (['posLog'] as File).listFiles()

        for (File file : files) {

            if(file.getName().startsWith(storeId.toString()+"_"+deviceId.toString())){

                file.delete()

            }

}

        def versionFile= ['posLog',"${storeId}_${deviceId}_${date2}.log"] as File

versionFile.text= objectsInJSON

output<< 'ok\n'

    }

    /**

* Copy fully {fileSize} bytes from input stream to output stream.

*/

    static void copy2(InputStream input, OutputStream output,int filesize)

            throws IOException{

        int totalLen= 0

        int length= 0

        try {

            byte[] buffer= new byte[1024]

            while (totalLen< filesize&& (length= input.read(buffer)) > 0) {

                output.write buffer,0, length

totalLen+= length

}

            output.flush()

        } catch (IOException e) {

            log.info"Failed on copy: read=" + totalLen

throw e

}

}

    static void doPutObject2(storeId, deviceId, tableName, objectClass, length, OutputStream output, InputStream input) {

        log.info"[${storeId}_${deviceId}]Going to get ${objectClass.toString()}objects2"

        String objectsInJSON= readLine(input)

        def jdbcConn= (getDbConnection(false).getReadWriteConnection() as JdbcDatabaseConnection).getInternalConnection()

        jdbcConn.autoCommit= false;//设置不自动提交

        Sql sql= new Sql(jdbcConn)

        List l= createGson().fromJson(objectsInJSON, List.class)//Json转成String[]

        String name= l.get(0)

        for (int i= 1; i< l.size(); i++) {

            String value= ""

            String[] s= l.get(i)

            for (String s2 : s) {

                if (i== 0) {

                    name+= ",${s2}"

                } else {

                    if (s2== null)

                        value+= ",${s2}"

                    else

                        value+= ",'${s2}'"

                }

}

            String sqlStr= "insert into ${tableName} (${name}) values (${value.substring(1)})"

            try {

                sql.execute(sqlStr,new ArrayList())//插入

            } catch (Exception e) {

                //java.sql.SQLException: 违反了 PRIMARY KEY 约束 'PK_POS_TRANHEAD'。不能在对象 'dbo.POS_TRANHEAD' 中插入重复键。

                if (e.message.contains("PRIMARY KEY")) {//重复插入跳过

                    log.info(e.getMessage())

                } else {

                    log.info(sqlStr)

                    log.error("insert into faild", e)

                    output<< 'ng\n'

                    jdbcConn.close()

                    log.info"[${storeId}_${deviceId}]Send: ng"

                    return

                }

}

}

        log.info("${tableName} insert success count ${length- 1}")

        jdbcConn.commit()//最后一起提交

        jdbcConn.close()

        output<< 'ok\n'

        log.info"[${storeId}_${deviceId}]Send: ok"

    }

    /**

* Server-side putObject protocol handler.

*


* Protocols:

*        Server                Client

* --------------------  --------------------

*  "putObject {store_id}_{device_id}{class_name}{#_of_objects}\n"

*          <----------------------

*{JSON stream of the n objects}\n

*          <----------------------

*            "ok\n" or "ng\n"

*          ---------------------->

*

*/

    static void doPutObject(storeId, deviceId, objectClass, numOfObjects, OutputStream output, InputStream input) {

        log.info"[${storeId}_${deviceId}]Going to get ${numOfObjects} ${objectClass.toString()}objects"

        String objectsInJSON= readLine(input)

        log.info"[${storeId}_${deviceId}]Receive: ${objectsInJSON}"

        def gson= createGson()

//        output << 'stream_ok\n'

        if (objectClass== MposSalesOrder) { // 点餐数据上传

            try {

                boolean succeeded= processUploadedMposSalesOrders(gson, objectsInJSON, storeId, deviceId)

                if (!succeeded) {

                    output<< 'ng\n'

                    log.info"[${storeId}_${deviceId}]Send: ng"

                    return

                }

            } catch (Exception e) {

                output<< 'ng\n'

                log.error('processUploadedMposSalesOrders', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } else if (objectClass== MposItemSet) { // 沽清数据上传

            try {

                def errorResponse= processUploadedMposItemSet(gson, objectsInJSON, storeId, deviceId)

                if (errorResponse) {

                    output<< errorResponse+ "\n"

                    log.info"[${storeId}_${deviceId}]Send: $errorResponse"

                    return

                }

            } catch (Exception e) {

                output<< 'ng\n'

                log.error('processUploadedMposItemSet', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } else if (objectClass== MposDiningTable) { // 桌子状态更新上传

            try {

                def errorResponse= processUploadedMposDiningTable(gson, objectsInJSON, storeId, deviceId)

                if (errorResponse) {

                    output<< errorResponse+ "\n"

                    log.info"[${storeId}_${deviceId}]Send: $errorResponse"

                    return

                }

            } catch (Exception e) {

                output<< 'ng\n'

                log.error('processUploadedMposDiningTable', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } else if (objectClass== MposTransaction) { // 交易数据上传

            try {

                processUploadedMposTransaction objectsInJSON

} catch (Exception e) {

                output<< 'ng\n'

                log.error('processUploadedMposTransaction', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } else if (objectClass== MposServerCommand) { // Server command

            def result= processServerCommand objectsInJSON

output<< result+ "\n"

            log.info"[${storeId}_${deviceId}]Send: ${result}"

            return

        } else if (objectClass== MposShift) {

            try {

                proocessUploadedShift objectsInJSON

} catch (Exception e) {

                output<< 'ng\n'

                log.error('proocessUploadedShift', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } else if (objectClass== MposShiftReport) {

            try {

                proocessUploadedPosShift objectsInJSON

} catch (Exception e) {

                output<< 'ng\n'

                log.error('proocessUploadedPosShift', e)

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

                return

            }

        } /*else if (objectClass == Pos_tranflow) {

proocessUploadedPosTranflow objectsInJSON

} else if (objectClass == Pos_tranhead) {

proocessUploadedPosTranhead objectsInJSON

        }*/ else {

            // Save to uploadDir: {object class name}_{device id}_{upload timestamp}.json

            def yyyymmddHHMMSS= String.format('%1$tY%1$tm%1$td%1$tH%1$tM%1$tS%1$tL',new Date())

            def saveFile= [uploadDir,"${objectClass.name}_${deviceId}_${yyyymmddHHMMSS}.json"] as File

saveFile.text= objectsInJSON

log.info"[${storeId}_${deviceId}]Create: $saveFile"

        }

        output<< 'ok\n'

        log.info"[${storeId}_${deviceId}]Send: ok"

    }

    static void proocessUploadedShift(String objectsInJSON) {

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List modelShifts= gson.fromJson(objectsInJSON, collectionType)

        def connSrc= getDbConnection(false)

        def sDao= DaoManager.createDao(connSrc, MposShift)

        modelShifts.each{ shift ->

sDao.callBatchTasks{

                shift.with{

                    fAccDate= new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(fAccDate))

                    if (serverType== 'SC')

                        fUploadFlag= 'N'    // Mark it uploaded

                    else

                        fUploadFlag= 'Y'    // Mark it uploaded

                }

                def deleteBuilder= sDao.deleteBuilder()

                deleteBuilder.where().eq('Warehouseid', shift.warehouseid).and().eq('fPosNo', shift.fPosNo).and().eq('fShift', shift.fShift).and().eq('custId', shift.custId)

                def rows= deleteBuilder.delete()

                if (rows> 0)

                    log.info"Delete existing $rows rows from Tc_Shift with fPosNo='${shift.fPosNo}' Warehouseid = '${shift.warehouseid}'"

                sDao.create shift

if (serverType!= 'SC')

                    if (shift.fAccDate== getInitialDate() && shift.fState!= 1) {//如果营业日期是1970-01-01,则更新该班别的营业日期

                        updateAccdate(getAccDate(shift.warehouseid), shift.fShift, shift.begFlowno ?:"", shift.endFlowno, shift.warehouseid, shift.custId)

                    }

}

}

}

    static void proocessUploadedPosShift(String objectsInJSON) {

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List modelShifts= gson.fromJson(objectsInJSON, collectionType)

        if (modelShifts.size() == 0)

            return

        def connSrc= getDbConnection(false)

        def sDao= DaoManager.createDao(connSrc, MposShiftReport)

        sDao.callBatchTasks{

            def deleteBuilder= sDao.deleteBuilder()

            modelShifts.each{ shift ->

deleteBuilder.where().eq('warehouseId', shift.warehouseId).and().eq('flowno', shift.flowno).and()

                        .eq('custId', shift.custId).and().eq('payWay', shift.payWay)

                def rows= deleteBuilder.delete()

                if (rows> 0)

                    log.info"Delete existing $rows rows from pos_shift with id='${modelShifts.flowno}'"

                shift.with{

                    //id = 0

                    if (serverType== 'SC')

                        uploadFlag= 'N'    // Mark it uploaded

                    else

                        uploadFlag= 'Y'    // Mark it uploaded

                }

                sDao.create shift

}

}

}

    static String processUploadedMposItemSet(Gson gson, String objectsInJSON, storeId, deviceId) {

        Type collectionType= new TypeToken>() {}.getType()

        List modelItemSet= gson.fromJson(objectsInJSON, collectionType)

        if (modelItemSet.size() == 0)

            return

        def connSrc= getDbConnection()

        def sDao= DaoManager.createDao(connSrc, MposItemSet)

        sDao.callBatchTasks{

            def deleteBuilder= sDao.deleteBuilder()

            deleteBuilder.where().eq('Warehouseid', storeId).and().eq('PosNO', deviceId)

            if(modelItemSet.get(0).tranType== 2){

                def rows= deleteBuilder.delete()

                if(rows){

                    log.info"Delete existing $rows rows from tbl_itemset with Warehouseid='$storeId' and PosNo='$deviceId'"

                }

            }else{

                def rows= deleteBuilder.delete()

                if(rows){

                    log.info"Delete existing $rows rows from tbl_itemset with Warehouseid='$storeId' and PosNo='$deviceId'"

                }

                modelItemSet.each{ set ->

sDao.create set

log.info"tbl_itemset inserted (id=${set.id},tranType=${set.tranType},pluno=${set.pluno},foodName=${set.foodName}...)"

//                    pushServer.pushString objectsInJSON

                }

}

}

}

    static synchronized String processUploadedMposDiningTable(Gson gson, String objectsInJSON, storeId, deviceId) {

        Type collectionType= new TypeToken>() {}.getType()

        List diningTables= gson.fromJson(objectsInJSON, collectionType)

        def connSrc= getDbConnection(false)

        def dao= DaoManager.createDao(connSrc, MposDiningTable)

        def errResponse= stateTransitionCheck(dao, diningTables)

        if (errResponse) {

            return errResponse

} else {

            for (diningTablein diningTables) {

                dao.update diningTable

log.info"[${storeId}_${deviceId}]Updated: $diningTable"

                // Push objectsInJSON

                pushServer.pushString objectsInJSON

}

            // 换桌需要调用后端存储过程

            def changingDiningTable= diningTables.size() == 2

            if (changingDiningTable) {

                def targetDiningTable= diningTables[1]

                proccessChangingDiningTable targetDiningTable, diningTables[0], connSrc

}

            return null

        }

}

    static void proccessChangingDiningTable(MposDiningTable targetDiningTable, MposDiningTable diningTable, ConnectionSource connSrc) {

        def sdao= DaoManager.createDao(connSrc, MposDiffSalesOrder)

        List diffSalesOrderList= sdao.queryForEq("flowno", targetDiningTable.tranFlowno)

        diffSalesOrderList*.roomNo= targetDiningTable.roomNo

diffSalesOrderList*.deskNo= targetDiningTable.deskNo

diffSalesOrderList*.deskName= targetDiningTable.deskName

int allQty= 0

        diffSalesOrderList.each{

            it.roomNo= targetDiningTable.roomNo

it.deskNo= targetDiningTable.deskNo

it.deskName= targetDiningTable.deskName

it.message= "换桌  原${diningTable.deskName} "

            allQty+= it.saleQty

sdao.update(it)

        }

        //打印控菜单

        if (dbConf.kitchen.printAll== 'Y') {

            try {

                lock.lock()

                diffSalesOrderList*.allQty= allQty

if (diffSalesOrderList.size() > 0) {

                    PrintServer printServer= new PrintServer()

                    printServer.printSaleOrder(diffSalesOrderList)

                }

            } catch (Exception e) {

                log.error(e)

            } finally {

                lock.unlock()

            }

}

}

    static synchronized boolean processUploadedMposSalesOrders(Gson gson, String objectsInJSON, storeId, deviceId) {

        Type collectionType= new TypeToken>() {}.getType()

        List salesOrders= gson.fromJson(objectsInJSON, collectionType)

        if (salesOrders) {

            log.info"Deserialized salesOrders: $salesOrders"

//            def connSrc = getDbConnection()

            def transConnSrc= getDbConnection(false)

            def tDao= DaoManager.createDao(transConnSrc, MposDiningTable)

            def sDao= DaoManager.createDao(transConnSrc, MposSalesOrder)

            def diffDao= DaoManager.createDao(transConnSrc, MposDiffSalesOrder)

            def diningTableId= salesOrders[0].diningTableId

def orderNumber= salesOrders[0].orderNumber

Map> diffSalesOrdersMap= [:]

            Map> diffSalesOrderCancelsMap= [:]

            boolean cancel= false

            try {

                if (diningTableId) {

                    def diningTable= tDao.queryForId(diningTableId)

                    if (diningTable?.orderNumber!= null && diningTable?.orderNumber!= '' &&  diningTable?.orderNumber!= orderNumber) {

                        log.info"processUploadedMposSalesOrders tableId = ${diningTableId} tableOrderNumber = ${diningTable?.orderNumber} orderNumber = $orderNumber"

                        return false

                    }

                    diningTable.orderNumber= orderNumber//设置交易单号

                    log.info"processUploadedMposSalesOrders tableId = ${diningTable} orderNumber = ${orderNumber}"

                    tDao.update(diningTable)

                }

                tDao.callBatchTasks{

                    // -> 手机下单时在发送sales orders之后,也负责发送dining table状态至后端(因为需要能更新后端桌子的

// 来客数、服务员、和备注等信息)。不过目前在结帐后的交易数据上传后,仍由后端修改重置桌子为idle,

// 并push桌子信息。

//def diningTable = tDao.queryForId(diningTableId)

//// 更新桌子对应的点单号

//diningTable.orderNumber = orderNumber

//if (diningTable.state == 'N')

//    diningTable.createDate = new Date() // 开桌时间

//// 桌子状态为被占用

//diningTable.state = 'Y'

//tDao.update(diningTable)

//List diffSalesOrderOrigs = mpos查询某张桌子的点单差异表数据(connSrc, storeId, deviceId, diningTableId)

                    List diffSalesOrderList= []

                    int allQty= 0

                    for (salesOrderin salesOrders) {

                        if (salesOrder.sellWay!= 'A' && salesOrder.sellWay!= 'B' && salesOrder.sellWay!= 'S')

                            continue

                        if (salesOrder.id== 0) {

                            sDao.create salesOrder

log.info"Create: $salesOrder"

                        } else {

                            sDao.update salesOrder

log.info"Update: $salesOrder"

                        }

                        if (!salesOrder.printName|| salesOrder.printFlag== 'N') {

                            log.info"${salesOrder.pluName} ${salesOrder.pluno} ${salesOrder.printName}not print"

                            continue

                        }

                        // 处理点单厨打表

                        log.info"salesOrder.id=" + salesOrder.id+ ",saleQty=" +

                                salesOrder.saleQty+ ",lastSaleQty=" + salesOrder.lastSaleQty

allQty+= salesOrder.saleQty

MposDiffSalesOrder diffSalesOrder= MposDiffSalesOrder.getAndCreateDiffSalesOrder(salesOrder)

                        if (diffSalesOrder) {

                            // 处理下diffSalesOrder.id, 以便成功update----目前厨打表只做insert

                            /*if (diffSalesOrderOrigs) {

for (diffSalesOrderOrig in diffSalesOrderOrigs) {

diffSalesOrderOrig = diffSalesOrderOrig as MposDiffSalesOrder

if (diffSalesOrderOrig.itemseq == salesOrder.lastItemseq

&& diffSalesOrderOrig.flowno == salesOrder.flowno

&& diffSalesOrderOrig.pluno == salesOrder.pluno) {

diffSalesOrder.id = diffSalesOrderOrig.id

}

}*/

                            // 创建diffSalesOrder

                            diffDao.create diffSalesOrder

//                            if (diffSalesOrder.deskNo == null)

//                                continue

                            log.info"Create: $diffSalesOrder"

                            salesOrder.lastSaleQty= salesOrder.saleQty

diffSalesOrderList.add(diffSalesOrder)

                        }

                        // -> 桌子状态改为由手机端发送

//// Push table status back

//pushServer.pushString gson.toJson([diningTable])

                    }

                    //打印控菜单

                    if (dbConf.kitchen.printAll== 'Y') {

                        try {

                            lock.lock()

                            diffSalesOrderList*.allQty= allQty

if (diffSalesOrderList.size() > 0) {

                                PrintServer printServer= new PrintServer()

                                printServer.printSaleOrder(diffSalesOrderList)

                            }

                        } catch (Exception e) {

                            log.error(e)

                        } finally {

                            lock.unlock()

                        }

}

                    // 手机点单: 调用存储过程:exec Proc_POS_APP 2,1,点单单号,''

//                    callStoredProcedure(1, salesOrders[0].flowno)

// -> 桌子状态改为由手机端发送

//// Push table status back

//pushServer.pushString gson.toJson([diningTable])

                }

            } catch (Exception e) {

                log.error'processUploadedMposSalesOrders() failed', e

return false

            }

}

        return true

    }

    static String stateTransitionCheck(Dao dao, List diningTables) {

        if (stlMap) {

            for (diningTablein diningTables) {

                def origDiningTable= dao.queryForId(diningTable.fId)

                def sourceState= (origDiningTable.state== '0' ?'N' : origDiningTable.state)

                def targetState= (diningTable.state== '0' ?'N' : diningTable.state)

                def expectedOldState= (diningTable.previousState== '0' ?'N' : diningTable.previousState)

                log.info"DiningTable.id=${diningTable.fId}: sourceState=$sourceState, expectedOldState=$expectedOldState, targetState=$targetState"

                if (sourceState!= expectedOldState|| // 状态被别人抢先更新(optimistic lock)

                        (sourceState!= targetState&& !stlMap[sourceState].contains(targetState))) {

                    // reject the transition

                    def response= "ng Reject the transition from $sourceState to $targetState"

                    return response

}

}

}

        return null

    }

    static String processServerCommand(String objectsInJSON) {

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List serverCommands= gson.fromJson(objectsInJSON, collectionType)

        for (serverCommandin serverCommands) {

            switch (serverCommand.command) {

                case 'refund':// 整笔退单

                    def orderNumber= serverCommand.argument

callStoredProcedure5, orderNumber

def connSrc= getDbConnection(false)

                    def hDao= DaoManager.createDao(connSrc, MposTransaction)

                    MposTransaction transaction= hDao.queryForEq("RtnFlowNo", orderNumber).get(0)

                    PrintServer.printTrans(transaction.flowno,'0', dbConf.PrintName,'','',1,false)

                    break

                case 'reprint':// 小票重印

                    def orderNumber= serverCommand.argument

callStoredProcedure4, orderNumber

PrintServer.printTrans(orderNumber,'1', dbConf.PrintName,'','',1,false)

                    break

                case 'date'://date, 比对系统日期

                    def clientDate= serverCommand.argument

def serverDate= new SimpleDateFormat("yyyy-MM-dd HH").format(new Date())

                    if (clientDate== serverDate)

                        return 'ok'

                    else

                        return 'ng'

                    break;

}

}

        return 'ok'

    }

    static void processUploadedMposTransaction(String objectsInJSON) {

        Type collectionType= new TypeToken>() {}.getType()

        def gson= createGson()

        List transactions= gson.fromJson(objectsInJSON, collectionType)

        log.info"Deserialized: $transactions"

        def connSrc= getDbConnection()

        def transConnSrc= getDbConnection(false)

        def hDao= DaoManager.createDao(transConnSrc, MposTransaction)

        def dDao= DaoManager.createDao(transConnSrc, MposLineItem)

        def pDao= DaoManager.createDao(transConnSrc, MposTransactionTender)

        def oDao= DaoManager.createDao(transConnSrc, MposO2oPayDtl)

        def cDao= DaoManager.createDao(transConnSrc, MposCardDtl)

        def tdDao= DaoManager.createDao(transConnSrc, MposTicketDtl)

        def todDao= DaoManager.createDao(transConnSrc, MposTakeOutTransaction)

        def tofdDao= DaoManager.createDao(transConnSrc, MposTakeOutTranflow)

        def tDao= DaoManager.createDao(transConnSrc, MposDiningTable)

        def tsDao= DaoManager.createDao(transConnSrc, MposTrantaste)

        transactions.each{ transaction ->

// 一笔交易的以下四张表的写入在一个事务中

            hDao.callBatchTasks{

                def print= false

                if (transaction.flowno) {

                    // Try to delete existing data that with the same order number

                    def storeId= transaction.warehouseid

def orderNumber= transaction.flowno

def custId= transaction.custId

def deleteBuilder= pDao.deleteBuilder()

                    deleteBuilder.where().eq('warehouseId', storeId).and().eq('flowno', orderNumber).and().eq('custId', custId)

                    def rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_tranpay with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= tsDao.deleteBuilder()

                    deleteBuilder.where().eq('warehouseId', storeId).and().eq('flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_trantaste with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= dDao.deleteBuilder()

                    deleteBuilder.where().eq('warehouseId', storeId).and().eq('flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_tranflow with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= oDao.deleteBuilder()

                    deleteBuilder.where().eq('Warehouseid', storeId).and().eq('Flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_carddtl with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= cDao.deleteBuilder()

                    deleteBuilder.where().eq('Warehouseid', storeId).and().eq('Flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_carddtl with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= hDao.deleteBuilder()

                    deleteBuilder.where().eq('warehouseId', storeId).and().eq('flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_o2opaydtl with warehouseId='$storeId' and flowno='$orderNumber'"

                    deleteBuilder= tdDao.deleteBuilder()

                    deleteBuilder.where().eq('Warehouseid', storeId).and().eq('Flowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from pos_TicketDtl with warehouseId='$storeId' and Flowno='$orderNumber'"

                    deleteBuilder= todDao.deleteBuilder()

                    deleteBuilder.where().eq('Warehouseid', storeId).and().eq('posFlowno', orderNumber).and().eq('custId', custId)

                    rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from takeOut_postranhead with warehouseId='$storeId' and posFlowno='$orderNumber'"

                    if (transaction.deskNo) {

//                        deleteBuilder = tDao.deleteBuilder()

//                        deleteBuilder.where().eq('warehouseId', storeId).and().eq('tranFlowno', orderNumber).and().eq('custId', custId)

//                        rows = deleteBuilder.delete()

//                        if (rows > 0)

//                            log.info "Delete existing $rows rows from pos_TicketDtl with warehouseId='$storeId' and flowno='$orderNumber'"

                    } else {

                        print= true

                    }

}

                transaction.with{

                    //id = 0              // Don't use the ID on client-side

                    if (serverType== 'SC')

                        uploadFlag= 'N'    // Mark it uploaded

                    else {

                        uploadFlag= 'Y'    // Mark it uploaded

//更新桌边点餐状态

                        if (transaction.jshopFlowno) {

                            def jDao= DaoManager.createDao(transConnSrc, MposJshopTransaction)

                            UpdateBuilder updateBuilder= jDao.updateBuilder()

                            updateBuilder.updateColumnValue('uploadFlag' ,'Y')

                                    .where().eq('flowNo', transaction.jshopFlowno).and().eq('warehouseid', transaction.warehouseid)

                            updateBuilder.update()

                        }

}

//                    if (sellway == 'O' || sellway == 'F')  // 开班/交班交易,手机端并没有给交易单号,所以这里补填上

//                        flowno = getNextOrderNumberOfDevice(connSrc, warehouseid, posNo)

                }

                hDao.create transaction

transaction.with{

                    log.info"pos_tranhead inserted (id=$id,posNo=$posNo,flowno=$flowno,SellWay=$sellway,saleAmt=$saleAmt)"

                }

                transaction.details.each{ lineItem ->

//lineItem.id = 0

                    if (serverType== 'SC')

                        lineItem.uploadflag= 'N'    // Mark it uploaded

                    else

                        lineItem.uploadflag= 'Y'    // Mark it uploaded

                    dDao.create lineItem

log.info"pos_tranflow inserted (id=${lineItem.id})"

                }

                transaction.payments.each{ tender ->

//tender.id = 0

                    if (serverType== 'SC')

                        tender.uploadFlag= 'N'

                    else

                        tender.uploadFlag= 'Y'

                    pDao.create tender

log.info"pos_tranpay inserted (id=${tender.id})"

                }

                transaction.trantastes.each{ trantaste ->

trantaste.id= 0

                    tsDao.create trantaste

log.info"pos_trantaste inserted (id=${trantaste.id})"

                }

                transaction.o2oPayDtls.each{ o2oPayDtl ->

o2oPayDtl.id= 0

                    if (serverType== 'SC')

                        o2oPayDtl.uploadFlag= 'N'

                    else

                        o2oPayDtl.uploadFlag= 'Y'

                    oDao.create o2oPayDtl

log.info"pos_o2opaydtl inserted (id=${o2oPayDtl.id})"

                }

                transaction.cardDtls.each{ cardDtl ->

cardDtl.id= 0

                    if (serverType== 'SC')

                        cardDtl.uploadFlag= 'N'

                    else

                        cardDtl.uploadFlag= 'Y'

                    cDao.create cardDtl

log.info"pos_carddtl inserted (id=${cardDtl.id})"

                }

                transaction.ticketDtls.each{ ticketDtls ->

if (serverType== 'SC')

                        ticketDtls.uploadFlag= 'N'

                    else

                        ticketDtls.uploadFlag= 'Y'

                    tdDao.create ticketDtls

log.info"pos_TicketDtl inserted (id=${ticketDtls.ticketNo})"

                }

                transaction.takeOutTrans.each{ takeOuttran ->

if (serverType== 'SC')

                        takeOuttran.uploadFlag= 'N'

                    else

                        takeOuttran.uploadFlag= 'Y'

                    todDao.create takeOuttran

log.info"takeOut_postranhead inserted (id=${takeOuttran.posFlowno})"

                    def deleteBuilder= tofdDao.deleteBuilder()

                    deleteBuilder.where().eq('fmId', takeOuttran.fmId)

                    int rows= deleteBuilder.delete()

                    if (rows> 0)

                        log.info"Delete existing $rows rows from takeOut_postranflow with fmId='$takeOuttran.fmId'"

                    takeOuttran.tranflows.each{tranflow ->

tofdDao.create(tranflow)

                        log.info"takeOut_postranflow inserted (id=${tranflow.fmId})"

                    }

}

                if (transaction.deskNo&& serverType== 'SC') {

                    def diningTable= tDao.queryBuilder().where().eq('deskNo', transaction.deskNo).queryForFirst()

                    if (diningTable) {

                        if (transaction.sellway!= 'B') { //退货不改变桌子状态

                            diningTable.transferToIdleState()

                        }

                        tDao.update diningTable

log.info"pos_deskInfo of transaction.deskNo=${transaction.deskNo}is back to idle."

                        // Push table status back

                        pushServer.pushString gson.toJson([diningTable])

                    }

}

                if (serverType== 'SC')

                    callStoredProcedureForTransaction transaction

if (print)

                    if (transaction.sellway== 'A' || transaction.sellway== 'B') {

                        //TODO

//                        PrintServer.printTrans(transaction.flowno, '0')

                    }

}

}

}

    // 手机 交易类型 to 存储过程参数 map

    static spParamMap= [

            A:3,// 手机结账    调用存储过程:exec Proc_POS_APP 2,3,交易单号,''

            C:2,// 交易取消    调用存储过程:exec Proc_POS_APP 2,2,点单单号,''

            B:5,// 整笔退餐    调用存储过程:exec Proc_POS_APP 2,5,交易单号,'

            O:3,// 开班

            F:3,// 交班

    ]

    // pc 交易类型 to 存储过程参数 map

    static sp2ParamMap= [

            A:6,// 手机结账    调用存储过程:exec Proc_POS_APP 2,3,交易单号,''

            C:2,// 交易取消    调用存储过程:exec Proc_POS_APP 2,2,点单单号,''

            B:5,// 整笔退餐    调用存储过程:exec Proc_POS_APP 2,5,交易单号,'

            O:3,// 开班

            F:3,// 交班

    ]

    /**

* 调用存储过程 for Transaction.

*/

    static void callStoredProcedureForTransaction(MposTransaction tran) {

        def param2= sp2ParamMap[tran.sellway]

        if (param2)

            callStoredProcedure(param2, tran.flowno)

//        if (tran.sellway == 'F') {

//            def connSrc = getDbConnection(false)

//            def dao = DaoManager.createDao(connSrc, MposShift)

//            def List shiftList = dao.queryBuilder().where()

//                    .eq('fState', '2').and().eq('warehouseId', tran.warehouseid).and().eq("fPosNo", tran.posNo)

//                    .query()

//            if (shiftList.size() > 0) {

//                def shiftNo = shiftList.get(shiftList.size() - 1)?.fShift

//                if (shiftNo) {

//                    PrintServer.printShift(shiftNo, tran.posNo, dbConf.PrintName)

//                }

//            }

//        }

    }

    /**

* 调用存储过程Proc_POS_APP。

*

    * @param param2 操作动作:

*

    *     

  • 1: 手机点单
  • *     

  • 2: 交易取消
  • *     

  • 3: 手机结账
  • *     

  • 4: 小票重印
  • *     

  • 5: 整笔退单
  • *

        * @param flowno 交易单号

    */

        static void callStoredProcedure(int param2, String flowno) {

            def db= getDbConnection()

            if (dbType.contains("sqlite") || dbType== 'MySQL')

                return

            def dbConn

    try {

                log.info"Call Proc_POS_APP(1, $param2, $flowno, '')"

                dbConn= db.getReadWriteConnection()

                def jdbcConn= (dbConnas JdbcDatabaseConnection).internalConnection

    def sql= new Sql(jdbcConn)

                sql.call'{call dbo.Proc_POS_APP(?, ?, ?, ?)}',[1, param2, flowno,'']

            } catch (Exception e) {

                e.printStackTrace()

                log.error"Call dbo.Proc_POS_APP(2, $param2, $flowno, '') failed", e

    } finally {

                if (dbConn) db.releaseConnection dbConn

    }

    }

    /*

    static void doDeleteObject(storeId, deviceId, objectClass, numOfObjects, OutputStream output, InputStream input) {

    log.info "[${storeId}_${deviceId}]Going to get ${numOfObjects} ${objectClass.toString()} objects"

    String objectsInJSON = readLine(input)

    log.info "[${storeId}_${deviceId}]Receive: ${objectsInJSON}"

    if (objectClass == MposSalesOrder) { // 点餐数据交易取消

    Type collectionType = new TypeToken>() {}.getType()

    def gson = createGson()

    List salesOrders = gson.fromJson(objectsInJSON, collectionType)

    if (salesOrders) {

    log.info "Deserialized salesOrders: $salesOrders"

    def connSrc = getDbConnection()

    def tDao = DaoManager.createDao(connSrc, MposDiningTable)

    def sDao = DaoManager.createDao(connSrc, MposSalesOrder)

    def diningTableId = salesOrders[0].diningTableId

    def orderNumber = salesOrders[0].orderNumber

    tDao.callBatchTasks {

    def diningTable = tDao.queryForId(diningTableId)

    try {

    List objects = mpos查询某张桌子的点单数据2(connSrc, storeId, deviceId, diningTableId)

    for (salesOrder in objects) {

    sDao.delete salesOrder

    log.info "delete: $salesOrder"

    }

    System.out.println('salesOrders1.size=' + salesOrders.size())

    objects ? System.out.println('objects.size=' + objects.size()) : System.out.println('objects is null')

    } catch (Exception e) {

    System.out.println('salesOrders2.size=' + salesOrders.size())

    for (salesOrder in salesOrders) {

    sDao.delete salesOrder

    log.info "delete: $salesOrder"

    }

    }

    // 清除桌子对应的点单号

    diningTable.orderNumber = ''

    // 桌子状态为被未占用

    diningTable.state = 'N'

    tDao.update(diningTable)

    // Push table status back

    pushServer.pushString gson.toJson([diningTable])

    }

    }

    }

    output << 'ok\n'

    log.info "[${storeId}_${deviceId}]Send: ok"

    }

    */

        /**

    * Server-side getObject protocol handler.

    *

    
    

    * Protocols:

    *        Server                Client

    * --------------------  --------------------

    *  "getObject {store_id}_{device_id}{class_name}\n"

    *          <----------------------

    *{JSON stream of objects}\n

    *          ---------------------->

    *            "ok\n" or "ng\n"

    *          <----------------------

    *

    */

        static void doGetObject(storeId, deviceId, Class objectClass, String argument,

    OutputStream output, InputStream input) {

            log.info"[${storeId}_${deviceId}]Going to get ${objectClass.toString()}objects"

            //output.withWriter('UTF-8') { writer ->

            def connSrc= getDbConnection()

            def transConnSrc= getDbConnection(false)

            List objects

    switch (objectClass) {

                case MposSalesOrder:// 查询某张桌子的点单数据

                    def diningTableId= argument.toInteger() // 参数会传入桌子的id

                    objects= mpos查询某张桌子的点单数据(transConnSrc, storeId, deviceId, diningTableId)

                    break

                case MposTransaction:// 如果要查詢历史交易,参数会传入桌子代号

                    objects= queryTodayTransactionForDiningTable(transConnSrc, storeId, argument)

                    break

                case MposShiftReport:// 如果要查詢交班报表,client端会带上日期

                    objects= queryShiftReportOfCertainDate(transConnSrc, storeId, argument)

                    break

                case MposDiningArea://获取桌子信息

                    objects= queryDiningArea(connSrc, transConnSrc)

                    break

                default:

    def dao= DaoManager.createDao(connSrc, objectClass)

                    objects= dao.queryForAll()

            }

    //        queryOtherAssociatedData connSrc, objects, objectClass

            def gson= createGson()

            def json= gson.toJson(objects)

            output<< json

    output<< '\n'

            output.flush()

            log.info"[${storeId}_${deviceId}]Send ${objectClass.simpleName}: ${json}"

            def response= readLine(input)

            if (response)

                log.info"[${storeId}_${deviceId}]Client response: ${response}"

            else

                log.info"[${storeId}_${deviceId}]Client disconnected."

        }

        /** 获取桌子信息 并且将mater库的桌子信息转到trans库里**/

        static List queryDiningArea(connSrc, transConnSrc) {

            def dao= DaoManager.createDao(connSrc, MposDiningArea)

            def dao2= DaoManager.createDao(transConnSrc, MposDiningArea)

            def tdao= DaoManager.createDao(connSrc, MposDiningTable)

            def tdao2= DaoManager.createDao(transConnSrc, MposDiningTable)

            if (masterVersion!= AppClient.masterVersion) {//当主档有更新时需要把master库的区域表和桌子表转到trans库对应的表中

                def areaList= dao.queryForAll()

                //2018-01-05 @pingping 将区域全删除再插入

                dao2.deleteBuilder().delete()

                for (MposDiningArea areain areaList) {

    //            List areaList2 = dao2.queryBuilder().where().eq("roomNo", area.roomNo).query()

    //            if (!areaList2) {

                    dao2.create(area)//桌子区域放到trans库

    //            } else {

    //                if (areaList2.get(0).roomName != area.roomName) {

    //                    areaList2.get(0).roomName = area.roomName

    //                    dao2.update(areaList2.get(0))

    //                }

    //            }

                }

                def tableList= tdao.queryForAll()

                //2018-01-05 @pingping 先删除未开桌的桌子,再插入

                DeleteBuilder deleteBuilder= tdao2.deleteBuilder()

                deleteBuilder.where().ne("State","Y")

                deleteBuilder.delete()

                for (MposDiningTable table : tableList) {

                    List list2= tdao2.queryBuilder().where().eq('fId', table.fId).query()

                    if (list2) {

                        if (list2.get(0).deskName!= table.deskName) {

                            list2.get(0).deskName= table.deskName

    tdao2.update(list2.get(0))

                        }

                        if (list2.get(0).roomNo!= table.roomNo) {

                            list2.get(0).roomNo= table.roomNo

    tdao2.update(list2.get(0))

                        }

                        if (list2.get(0).tranFlowno!= '' && list2.get(0).state!= 'Y') {

                            list2.get(0).tranFlowno= table.tranFlowno

    tdao2.update(list2.get(0))

                        }

                    } else {

                        tdao2.create(table)//桌子信息放到trans库

                    }

    }

                masterVersion= AppClient.masterVersion

    }

            def objects= dao2.queryForAll()//取trans库的桌子区域

            for (MposDiningArea areain objects) {

                def list= tdao2.queryForEq('roomNo', area.roomNo)//取trans库的桌子信息

                if (list.size() == 0)

                    masterVersion= ""

                area.diningTables= list

    }

            return objects

    }

        /** 判断交易是否已经被退货。 */

        static boolean isTransactonRefund(connSrc, storeId, deviceId, flowno) {

            def tDao= DaoManager.createDao(connSrc, MposTransaction)

            GenericRawResults rawResults= tDao.queryRaw(

                    "select 1 from pos_tranhead where WarehouseID='${storeId}' and rtnflowno = '${flowno}'")

            List results= rawResults.getResults()

            if (results) {

                String[] resultArray= results.get(0)

                if (resultArray) {

                    return true

                }

    }

            return false

        }

        /** 求某个手机本日的下个交易单号。从pos_tranflowhd和pos_tranhead中取最大者+1。 */

        static String getNextOrderNumberOfDevice(connSrc, storeId, deviceId) {

            def sDao= DaoManager.createDao(connSrc, MposSalesOrder)

            def yyyymmdd= String.format('%1$tY%1$tm%1$td',new Date())

            deviceId= String.format('%02d', deviceId.toInteger()) // two-digit device ID

            GenericRawResults rawResults= sDao.queryRaw(

                    "select MAX(flowno) from pos_tranflowhd where WarehouseID='${storeId}' and flowno like '${deviceId}${yyyymmdd}%'")

            List results= rawResults.getResults()

            int maxSequence= 0

            if (results) {

                String[] resultArray= results.get(0)

                if (resultArray) {

                    String maxOrderNumber= resultArray[0]

                    maxSequence= (maxOrderNumber?.substring(10) ?:'0').toInteger()

                }

    }

            maxSequence++

            rawResults= sDao.queryRaw(

                    "select MAX(flowno) from pos_tranhead where WarehouseID='${storeId}' and flowno like '${deviceId}${yyyymmdd}%'")

            results= rawResults.getResults()

            if (results) {

                String[] resultArray= results.get(0)

                if (resultArray) {

                    String maxOrderNumber= resultArray[0]

                    maxSequence= Math.max((maxOrderNumber?.substring(10) ?:'0').toInteger() + 1, maxSequence)

                }

    }

            def newSequence= String.format('%04d', maxSequence) // four-digit order number

            return "${deviceId}${yyyymmdd}${newSequence}"

        }

        /** 查询本日某张桌子的交易。 */

        static List queryTodayTransactionForDiningTable(connSrc, storeId, diningTableCode) {

            def today= new SimpleDateFormat("yyyy-MM-dd").format(new Date())

            def dao= DaoManager.createDao(connSrc, MposTransaction)

            dao.queryBuilder().where()

                    .eq('accdate', today).and().eq('deskNo', diningTableCode)

                    .query()

        }

        static List queryShiftReportOfCertainDate(connSrc, storeId, date) {

            def dao= DaoManager.createDao(connSrc, MposShiftReport)

            dao.queryBuilder()

                    .orderBy('flowno',false)

                    .where().eq('warehouseId', storeId).and().eq('accdate', date)

                    .query()

        }

        static List mpos查询某张桌子的点单数据(transConnSrc, storeId, deviceId, diningTableId) {

            def tDao= DaoManager.createDao(transConnSrc, MposDiningTable)

            def diningTable= tDao.queryForId(diningTableId)

            def orderNo= diningTable.tranFlowno// 当前对应的点单号

            def sDao= DaoManager.createDao(transConnSrc, MposSalesOrder)

            List salesOrders

    if (orderNo) {

                salesOrders= sDao.queryBuilder()

                        .orderBy('id',true)

                        .where().eq('flowno', orderNo)

                        .query()

            }

            if (!salesOrders) { // 如果找不到这张桌子的任何点餐数据,就生成一笔空记录,里面只包含了新的点单号

                def nextOrderNumber= getNextOrderNumberOfDevice(getDbConnection(false), storeId, deviceId)

                salesOrders= [new MposSalesOrder(flowno: nextOrderNumber, diningTableId: diningTableId)]

            } else {

                // Fill some non-database fields

                salesOrders.each{ MposSalesOrder salesOrder ->

    salesOrder.diningTableId= diningTableId

    salesOrder.lastSaleQty= salesOrder.saleQty.setScale(3,4)

                    salesOrder.lastItemseq= salesOrder.itemseq.setScale(0)

                }

    }

            return salesOrders

    }

    //    static List mpos查询某张桌子的点单数据2(connSrc, storeId, deviceId, diningTableId) {

    //        def tDao = DaoManager.createDao(connSrc, MposDiningTable)

    //        def diningTable = tDao.queryForId(diningTableId)

    //        def orderNo = diningTable.tranFlowno // 当前对应的点单号

    //        def sDao = DaoManager.createDao(connSrc, MposSalesOrder)

    //        List salesOrders

    //        if (orderNo) {

    //            salesOrders = sDao.queryBuilder()

    //                    .orderBy('itemseq', true)

    //                    .where().eq('flowno', orderNo)

    //                    .query()

    //        }

    //        if (!salesOrders) { // 如果找不到这张桌子的任何点餐数据,返回null

    //            return salesOrders

    //        } else {

    //            // Fill some non-database fields

    //            salesOrders.each { MposSalesOrder salesOrder ->

    //                salesOrder.diningTableId = diningTableId

    //                salesOrder.lastSaleQty = salesOrder.saleQty.setScale(0)

    //                salesOrder.lastItemseq = salesOrder.itemseq.setScale(0)

    //            }

    //        }

    //        return salesOrders

    //    }

    //    static List mpos查询某张桌子的点单差异表数据(connSrc, storeId, deviceId, diningTableId) {

    //        def tDao = DaoManager.createDao(connSrc, MposDiningTable)

    //        def diningTable = tDao.queryForId(diningTableId)

    //        def orderNo = diningTable.tranFlowno // 当前对应的点单号

    //        def diffDao = DaoManager.createDao(connSrc, MposDiffSalesOrder)

    //        List diffSalesOrders

    //        if (orderNo) {

    //            try {

    //                diffSalesOrders = diffDao.queryBuilder()

    //                        .orderBy('itemseq', true)

    //                        .where().eq('flowno', orderNo)

    //                        .query()

    //            } catch (Exception e) {

    //                log.error e.message, e

    //            }

    //        }

    //        return diffSalesOrders  // 如果找不到这张桌子的任何点餐数据,返回null

    //        // Fill some non-database fields

    //        // diffSalesOrders.each { MposDiffSalesOrder diffSalesOrder ->

    //        //    diffSalesOrder.diningTableId = diningTableId

    //        // }

    //    }

        static void queryOtherAssociatedData(ConnectionSource connSrc, List objects, Class objectClass) {

            if (objectClass== MposDiningArea) {

                def dao= DaoManager.createDao(connSrc, MposDiningTable)

                for (MposDiningArea areain objects) {

                    area.diningTables= dao.queryForEq('roomNo', area.roomNo)

                    if (!area.diningTables)

                        continue

                    // Fix table state if it is inconsistent with its order number

    //                for (MposDiningTable table in area.diningTables) {

    //                    if (table.orderNumber && table.state != 'Y') {

    //                        table.state = 'Y'

    //                        dao.update table

    //                    } else if (!table.orderNumber && table.state != 'N') {

    //                        table.state = 'N'

    //                        dao.update table

    //                    }

    //                }

                }

    }

    }

        static void doGetApkVersion(storeId, deviceId, OutputStream output, InputStream input) {

            // Find latest apk's release note JSON file

            def fs= ('apk' as File).listFiles()?.sort()?.collect{ it.name}

            def jsonFile= fs ? fs[-1] :null

            log.info"[${storeId}_${deviceId}]The last file in apk/: ${jsonFile}"

            if (jsonFile?.endsWith('.json'))

                doGetFile storeId, deviceId,['apk', jsonFile] as File, output, input

    else {

                log.info"[${deviceId}]Cannot find any latest apk version info."

                output<< '0\n'

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            }

    }

        /**

    * Server-side getPosVersion protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *        "getPosVersion {store_id}_{device_id}\n"

    *          <----------------------

    *            "{json_file_size}\n"

    *          ---------------------->

    *            "{file content}"

    *          ---------------------->

    *            "ok\n" or "ng\n"

    *          <----------------------

    *

    */

        static void doGetPosVersion(storeId, deviceId, OutputStream output, InputStream input) {

            // Find latest pos's release note JSON file

            def fs= (('update/' + deviceId) as File).listFiles(new FilenameFilter() {

                @Override

    boolean accept(File dir, String name) {

                    log.info'===== ' + name

    return name.lastIndexOf('.json') > 0

                }

            })?.sort()?.collect{ it.name}

            def jsonFile= fs ? fs[-1] :null

            log.info"[${storeId}_${deviceId}]The last file in pos/: ${jsonFile}"

            if (jsonFile?.endsWith('.json'))

                doGetFile storeId, deviceId,['update/' + deviceId, jsonFile] as File, output, input

    else {

                log.info"[${deviceId}]Cannot find any latest pos version info."

                output<< '0\n'

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            }

    }

        static void upPosVersion(String custId, String storeId, String deviceId, String version, String type, String date, OutputStream output, InputStream input) {

            if (serverType== 'HQ') {

                try {

                    def jdbcConn= (getDbConnection(false).getReadWriteConnection() as JdbcDatabaseConnection).getInternalConnection()

                    Sql sql= new Sql(jdbcConn)

                    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    String todayStr= sdf.format(new Date());

    String sqlStr= "select id from pos_masterversion where custId='${custId}' and warehouseId='${storeId}' " +

                            "and posNo='${deviceId}' and type='${type}'"

                    log.info(sqlStr)

                    def connSrc= getDbConnection()

                    def sDao= DaoManager.createDao(connSrc, MposItemSet)

                    GenericRawResults rawResults= sDao.queryRaw(sqlStr)

                    if (rawResults.size() > 0) {

                        sqlStr= "update pos_masterversion set version='${version}', updateTime='${todayStr}', memo = '${date ?:''}' " +

                                "where custId='${custId}' and warehouseId='${storeId}' and posNo='${deviceId}' and type='${type}'"

                    } else {

                        sqlStr= "insert into pos_masterversion values('${custId}','${storeId}','${deviceId}','${version}','${type}','${todayStr}','${date ?:''}')"

                    }

                    log.info(sqlStr)

                    sql.execute(sqlStr)

                } catch (Exception e) {

                    log.warn"[${storeId}_${deviceId}]upPosVersion failed", e

    log.info(e.getMessage())

                    if (e.getMessage().contains('maximum connections reached')) {

                        System.exit(1)

                    }

    }

    }

    }

        /**

    * Server-side getMasterVersion protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *        "getMasterVersion {store_id}_{device_id}\n"

    *          <----------------------

    *            "{json_file_size}\n"  or -1 if upload directory is not empty

    *          ---------------------->

    *            "{file content}"

    *          ---------------------->

    *            "ok\n" or "ng\n"

    *          <----------------------

    *

    */

        static void doGetMasterVersion(storeId, deviceId, OutputStream output, InputStream input) {

            // Find latest master's release note JSON file

            def dirStr= 'db'

            if (serverType== 'HQ')

                dirStr= "db/${deviceId}/${storeId}"

            def fs= (dirStras File).listFiles()?.sort()?.collect{ it.name}

            def jsonFile= fs ? fs[-1] :null

            if (jsonFile?.endsWith('.json'))

                doGetFile storeId, deviceId,[dirStr, jsonFile] as File, output, input

    else {

                log.info"[${storeId}_${deviceId}]Cannot find any latest master version info."

                output<< '0\n'

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            }

    }

        /**

    * Server-side putFile protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *          "checkSellOff {store_id}_{device_id}{pluno}\n"

    *          <----------------------

    *            "ok\n" or "nofound\n" or "ng\n"

    *          ---------------------->

    *

    *

    */

        static void checkSellOff(storeId, deviceId, String pluno, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection()

                def sDao= DaoManager.createDao(connSrc, MposItemSet)

                GenericRawResults rawResults= sDao.queryRaw(

                        "select tranType from tbl_itemset where tranType=1 and pluno = '${pluno}'")

                List results= rawResults.getResults()

                if (results) {

                    output<< 'off\n'

                    log.info"[${storeId}_${deviceId}]Send ok."

                } else {

                    output<< 'ok\n'

                    log.info"[${storeId}_${deviceId}]Send nofound."

                }

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId}]checkSellOff failed", e

    output<< 'ng\n'

            }

            def response= readLine(input)

            if (response)

                log.info"[${storeId}_${deviceId}]Client response: ${response}"

            else

                log.info"[${storeId}_${deviceId}]Client disconnected."

        }

        /**

    * Server-side getTransaction protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *          "getTransaction {store_id}_{device_id}{flowno}\n"

    *          <----------------------

    *            transaction / null

    *          ---------------------->

    *

    *

    */

        static void getTransaction(storeId, deviceId, String flowno, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection(false)

                if (isTransactonRefund(connSrc, storeId,'', flowno)) {

                    output<< 'ng refund\n'

                    return

                }

                def hDao= DaoManager.createDao(connSrc, MposTransaction)

                def dDao= DaoManager.createDao(connSrc, MposLineItem)

                def pDao= DaoManager.createDao(connSrc, MposTransactionTender)

                def tDao= DaoManager.createDao(connSrc, MposTicketDtl)

                def oDao= DaoManager.createDao(connSrc, MposO2oPayDtl)

                def cDao= DaoManager.createDao(connSrc, MposCardDtl)

                List transactions= hDao.queryBuilder()

                        .where().eq('warehouseId', storeId).and().eq('flowno', flowno)

                        .query()

                MposTransaction transaction

    if (transactions) {

                    transaction= transactions[0]

                    if (transaction.sellway!= 'A') {

                        output<< 'ng sale\n'

                        return

                    }

                    transaction.details= dDao.queryBuilder().where().eq('warehouseId', storeId).and().eq('flowno', flowno)

                            .query()

                    transaction.payments= pDao.queryBuilder().where().eq('warehouseId', storeId).and().eq('flowno', flowno)

                            .query()

                    transaction.o2oPayDtls= oDao.queryBuilder().where().eq('Warehouseid', storeId).and().eq('Flowno', flowno)

                            .query()

                    transaction.cardDtls= cDao.queryBuilder().where().eq('Warehouseid', storeId).and().eq('Flowno', flowno)

                            .query()

                    transaction.ticketDtls= tDao.queryBuilder().where().eq('WarehouseID', storeId).and().eq('Flowno', flowno)

                            .query()

                }

                def objects= transaction ?[transaction] :[]

                def gson= createGson()

                def json= gson.toJson(objects)

                output<< json

    output<< '\n'

                output.flush()

                log.info"[${storeId}_${deviceId}]Send ${MposTransaction.simpleName}: ${json}"

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId} ${flowno}]getTransaction failed", e

    output<< 'ng\n'

            }

    }

        /**

    * Server-side getTransactionInfos protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *          "getTransactionInfos {store_id}_{device_id}{accday}\n"

    *          <----------------------

    *            transactions / null

    *          ---------------------->

    *

    *

    */

        static void getTransactionInfos(storeId, deviceId, String diningTableCode, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection(false)

                def today= new SimpleDateFormat("yyyy-MM-dd").format(new Date())

                def dao= DaoManager.createDao(connSrc, MposTransaction)

                List transactions= dao.queryBuilder().where()

                        .eq('accdate', today).and().eq('deskNo', diningTableCode)

                        .and().in('sellway','A','B')

                        .query()

                Map map= [:]

                transactions.each{

                    map[it.flowno] = it

    }

                GenericRawResults rawResults= dao.queryRaw(

                        """select RtnFlowNo from pos_tranhead where RtnFlowNo in

    (select flowno from pos_tranhead where Accdate='${today}' and Sellway = 'A')""")

                List results= rawResults.getResults()

                if (results) {

                    results.each{ String[] rtnFlowNo ->

    MposTransaction t= map[rtnFlowNo[0]]

                        if (t)

                            t.rtnFlowNo= 'Y'

                    }

    }

                def gson= createGson()

                def json= gson.toJson(transactions)

                output<< json

    output<< '\n'

                output.flush()

                log.info"[${storeId}_${deviceId}]Send ${MposTransaction.simpleName}: ${json}"

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId} ${diningTableCode}]getTransactionInfos failed", e

    output<< 'ng\n'

            }

    }

        /**

    * Server-side getTransactionsAndShifts protocol handler.

    *

    
    

    *        Server                Client

    * --------------------  --------------------

    *          "getTransactionsAndShifts ${storeId}_${posNo}_${custId} ${startDate} ${endDate}\n"

    *          <----------------------

    *            transactions / null

    *          ---------------------->

    *          shifts / null

    *          ---------------------->

    *          shiftReports / null

    *          ---------------------->

    *

    *

    */

        static void getTransactionsAndShifts(custId, storeId, deviceId, startDate, endDate, OutputStream output, InputStream input) {

            try {

                SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    Date sDate= sdf.parse(startDate+' 00:00:00');

    Date eDate= sdf.parse(endDate+' 23:59:59');

    startDate= sdf.format(sDate)

                endDate= sdf.format(eDate)

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposTransaction)

                def dDao= DaoManager.createDao(connSrc, MposLineItem)

                def pDao= DaoManager.createDao(connSrc, MposTransactionTender)

                def tDao= DaoManager.createDao(connSrc, MposTicketDtl)

                def oDao= DaoManager.createDao(connSrc, MposO2oPayDtl)

                def cDao= DaoManager.createDao(connSrc, MposCardDtl)

                def sDao= DaoManager.createDao(connSrc, MposShift)

                def srDao= DaoManager.createDao(connSrc, MposShiftReport)

                List transactions= dao.queryBuilder().where().eq('custId', custId).and()

                        .eq('warehouseId', storeId).and().eq('PosNo', deviceId).and().between('OperDate', sDate, eDate)

    //                    .le('Accdate', endDate).and().ge('Accdate', startDate)

                        .query()

                for (MposTransaction transaction : transactions) {

                    transaction.details= dDao.queryBuilder().where().eq('warehouseId', storeId).and().eq('flowno', transaction.flowno)

                            .query()

                    transaction.payments= pDao.queryBuilder().where().eq('warehouseId', storeId).and().eq('flowno', transaction.flowno)

                            .query()

                    transaction.o2oPayDtls= oDao.queryBuilder().where().eq('Warehouseid', storeId).and().eq('Flowno', transaction.flowno)

                            .query()

                    transaction.cardDtls= cDao.queryBuilder().where().eq('Warehouseid', storeId).and().eq('Flowno', transaction.flowno)

                            .query()

                    transaction.ticketDtls= tDao.queryBuilder().where().eq('WarehouseID', storeId).and().eq('Flowno', transaction.flowno)

                            .query()

                }

                List shifts= sDao.queryBuilder().where().eq('custId', custId).and()

                        .eq('warehouseId', storeId).and().eq('fPosNo', deviceId).and().between('fBegDate', sDate, eDate)

    //                    .le('fAccdate', eDate).and().ge('fAccdate', sDate)

                        .query()

                List shiftReports= srDao.queryBuilder().where().eq('custId', custId).and()

                        .eq('warehouseId', storeId).and().eq('PosNo', deviceId).and().between('operDate', sDate, eDate)

    //                    .le('accdate', endDate).and().ge('accdate', startDate)

                        .query()

                def gson= createGson()

                def json= gson.toJson(transactions)

                output<< json

    output<< '\n'

                output.flush()

                log.info"[${storeId}_${deviceId}]Send : ${json}"

                json= gson.toJson(shifts)

                output<< json

    output<< '\n'

                output.flush()

                log.info"[${storeId}_${deviceId}]Send : ${json}"

                json= gson.toJson(shiftReports)

                output<< json

    output<< '\n'

                output.flush()

                log.info"[${storeId}_${deviceId}]Send : ${json}"

                def response= readLine(input)

                if (response)

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                else

                    log.info"[${storeId}_${deviceId}]Client disconnected."

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId}]getTransactionInfos failed", e

    output<< 'ng\n'

            }

    }

        //获取未打印的厨打

        static void getDiffSalesOrders(String posNo, String period, OutputStream output, InputStream input) {

            try {

                Date now= new Date();

    Calendar calendar= Calendar.getInstance();

    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

    String yesterdayStr= sdf.format(now);

    Date yesterday= sdf.parse(yesterdayStr)

                calendar.setTime(now);

    calendar.add(Calendar.SECOND,-Integer.parseInt(period));

    Date before= calendar.getTime();

    sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    String beforeStr= sdf.format(before);

    before= sdf.parse(beforeStr)

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposDiffSalesOrder)

                List diffSalesOrders= dao.queryBuilder().where().eq('PrintFlag','N').and()

                        .eq('PosNo', posNo).and().between('operDate', yesterday, before)

    //                    .le('Accdate', endDate).and().ge('Accdate', startDate)

                        .query()

                def gson= createGson()

                def json= gson.toJson(diffSalesOrders)

                output<< json

    output<< '\n'

                output.flush()

                log.info"Send : ${json}"

                def response= readLine(input)

                if (response)

                    log.info"Client response: ${response}"

                else

                    log.info"Client disconnected."

            } catch (Exception e) {

                log.warn"getDiffSalesOrders failed", e

    output<< 'ng\n'

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

    }

    }

        //获取沽清商品

        static void getMposItemSets(String storeId, String posNo, String period, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposItemSet)

                List mposItemSet= dao.queryBuilder().where().eq('Warehouseid', storeId).and()

                        .ne('PosNO', posNo).query()

    //                    .le('Accdate', endDate).and().ge('Accdate', startDate)

                def gson= createGson()

                def json= gson.toJson(mposItemSet)

                output<< json

    output<< '\n'

                output.flush()

                log.info"Send : ${json}"

                def response= readLine(input)

                if (response)

                    log.info"Client response: ${response}"

                else

                    log.info"Client disconnected."

            } catch (Exception e) {

                log.warn"getMposItemSets failed", e

    output<< 'ng\n'

                if (e.getMessage().contains('maximum connections reached')) {

                    System.exit(1)

                }

    }

    }

        //获取未打印的厨打

        static void getPlatformOrders(String storeId, String uploadFlag, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposJshopTransaction)

                def fDao= DaoManager.createDao(connSrc, MposJshopTranflow)

                def pDao= DaoManager.createDao(connSrc, MposJshopTranpay)

                List diffSalesOrders= []

                List diffSalesOrders2= new ArrayList()

                Date date1= new Date()

                date1.setHours(0);

    date1.setMinutes(0);

    date1.setSeconds(0);

    Calendar calendar= new GregorianCalendar();

    calendar.setTime(date1);

    calendar.add(calendar.DATE,1);//把日期往后增加一天.整数往后推,负数往前移动

                Date date2= calendar.getTime();

    if (uploadFlag== 'N') {

                    diffSalesOrders= dao.queryBuilder().orderBy('operDate',true)

                            .where().eq('uploadFlag','N').and().eq('warehouseid', storeId)

                            .and().in('sellway','A','B').and().ge("operDate", date1)

                            .and().le("operDate", date2).query()

                    diffSalesOrders.each{

                        diffSalesOrders2<< it

    }

                    for (MposJshopTransaction jshopTran : diffSalesOrders) {

                        if (jshopTran.rtnFlowNo&& jshopTran.rtnFlowNo!= "") {

                            for (MposJshopTransaction jshop : diffSalesOrders) {

                                if (jshopTran.rtnFlowNo== jshop.flowno) {

                                    diffSalesOrders2.remove(jshopTran)

                                    diffSalesOrders2.remove(jshop)

                                    break

                                }

    }

    }

    }

                } else if (uploadFlag== 'Y') {

                    diffSalesOrders2= dao.queryBuilder().orderBy('operDate',false).where().eq('uploadFlag','Y').and()

                            .eq('warehouseid', storeId).and().in('sellway','A','B').query()

                }

                for (MposJshopTransaction jTran : diffSalesOrders2) {

                    jTran.tranflows= fDao.queryBuilder().orderBy("itemseq",true).where().eq('warehouseid', storeId).and().eq('flowno',jTran.flowno).query()

                }

                for (MposJshopTransaction jTran : diffSalesOrders2) {

                    jTran.tranpays= pDao.queryBuilder().where().eq('warehouseid', storeId).and().eq('flowno',jTran.flowno).query()

                }

                def gson= createGson()

                def json= gson.toJson(diffSalesOrders2)

                output<< json

    output<< '\n'

                output.flush()

                log.info"Send : ${json}"

            } catch (Exception e) {

                log.warn"getPlatformOrders failed", e

    output<< 'ng\n'

            }

    }

        //获取未打印的厨打

        static void platformOrderUpdate(String storeId, String flowno, String flag, OutputStream output, InputStream input) {

            try {

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposJshopTransaction)

                dao.callBatchTasks{

                    List diffSalesOrders= dao.queryBuilder().where().eq('flowno', flowno).and()

                            .eq('warehouseid', storeId).query()

                    MposJshopTransaction diff= diffSalesOrders ? diffSalesOrders[0] :null

                    if (diff) {

                        if (flag== 'S') {

                            if (diff.uploadFlag== 'N') {

                                diff.uploadFlag= 'S'

                                dao.update(diff)

                                output<< 'ok\n'

                            } else {

                                output<< 'ng\n'

                            }

                        } else if (flag== 'Y') {

                            diff.uploadFlag= 'Y'

                            dao.update(diff)

                            String sql= "update jshop_orderform set order_status = 30 where pos_sale_flowno = '${flowno}' and store_no = '${storeId}';"

                            dao.queryRaw(sql)

                            sql= "insert into jshop_order_log(addtime,deletestatus,log_info,of_id) select getdate(),0,'已出单',id " +

                                    "from jshop_orderform where pos_sale_flowno = '${flowno}' and store_no = '${storeId}';"

                            dao.queryRaw(sql)

                            output<< 'ok\n'

                        }

    }

                    output.flush()

                    log.info"Send :"

                }

            } catch (Exception e) {

                log.warn"platformOrderUpdate failed", e

    output<< 'error\n'

            }

    }

        //修改未打印的厨打为已打印

        static void kitchenPlayUpdate(id, output, input) {

            try {

                def connSrc= getDbConnection(false)

                def dao= DaoManager.createDao(connSrc, MposDiffSalesOrder)

                UpdateBuilder supdateBuilder= dao.updateBuilder()

                supdateBuilder.updateColumnValue('PrintFlag','Y').where().eq('id', id)

                int rows= supdateBuilder.update()

                output<< 'ok\n'

            } catch (Exception e) {

                log.warn"kitchenPlayUpdate failed", e

    output<< 'ng\n'

            }

    }

        /**

    * 获取电子发票  一定要填写MposTransaction.eInvoice和MposTransaction.eInvoiceFlowNo

    * 接收参数data 数据以【|】分隔 退货才能用到

    *  第一段  原发票代码

    *  第二段  原发票号码

    *

    * 返回

    *  ng            失败

    *  eInvoiceSet  电子发票未设定

    *  其它          电子发票开票成功  数据以【|】分隔  说明如下:

    *    第一段  发票流水号    记录到tranhead.EInvoiceFlowNo字段

    *    第二段  发票代码      记录到tranhead.EInvoiceFPDM字段

    *    第三段  发票号码      记录到tranhead.EInvoiceFPHM字段

    *    第四段  发票下载URL  记录到tranhead.EInvoicePDFURL字段,并将URL生成二维码打印到小票上

    *

    */

        static void getEInvoice(String custId, String storeId, String deviceId, String data, OutputStream output, InputStream input) {

            log.info("[${custId}_${storeId}_${deviceId}] data ${data}")

            String objectsInJSON= readLine(input)

            log.info"[${custId}_${storeId}_${deviceId}]Receive: ${objectsInJSON}"

            Type collectionType= new TypeToken>() {}.getType()

            def gson= createGson()

            List transactions= gson.fromJson(objectsInJSON, collectionType)

            if (transactions) {

                def connSrc= getDbConnection()

                String result= EInvoiceUtil.getDFXJ1001(transactions.get(0), data, custId, connSrc)

                output<< "${result}\n"

            } else {

                output<< 'ng\n'

            }

    }

        /**

    * 接收参数data 数据以【|】分隔

    *  第一段为类型                            13:微支付 28:支付宝

    *  第二段为类型                            1:消费 2:查询 3:撤销 4:退货

    *  第三段为订单号                          唯一编号,消费/查询/撤销/退货都要用到单号

    *  第四段为金额                            消费/退货时用到,金额都为正数

    *  第五段为消费付款码/退货原订单号            消费时传付款码,退货时传原订单号

    *  第六段为消费商品说明/退货原接口交易流水号  消费时传一个两个商品名称就可以了,退货时传接口返回的交易流水号

    *  第七段为退货原接口非码交易流水号          退货时传接口返回的非码交易流水号 ,只有非码接口才有

    *  第八段为收银员编号                      消费/退货(非码)时用到

    *

    * 返回参数result 数据以【|】分隔

    *  第一段为状态                            0:成功 1:失败 2:等待付款(建议每53秒查询一次)

    *  第二段为提示信息                        成功/失败的文字说明

    *  第三段为接口返回的订单号                  消费/退货成功时才返回

    *  第四段为接口返回的顾客账号                消费成功时才返回

    *  第五段为接口返回的支付渠道(非码)          消费成功时才返回

    *  第六段为接口返回的非码支付流水号(非码)      消费成功时才返回

    *

    */

        static void getO2oPay(String custId, String storeId, String deviceId, String data, OutputStream output, InputStream input) {

            if (o2oPayMap.containsKey(data)) {

                String result= o2oPayMap.get(data)

                log.info("[${storeId}_${deviceId}_${custId}] retry ${result}")

                output<< "${result}\n"

                return

            }

            String result= PayUtil.getO2oPay(custId, storeId, deviceId, data, getDbConnection());

    log.info("[${storeId}_${deviceId}_${custId}] ${result}")

            o2oPayMap.put(data, result)

            output<< "${result}\n"

        }

        static Map o2oPayMap= [:]

        static void getSalesOrders(storeId, deviceId, String diningTableIds, OutputStream output, InputStream input) {

            try {

    //            def connSrc = getDbConnection()

                def transConnSrc= getDbConnection(false)

                def tDao= DaoManager.createDao(transConnSrc, MposDiningTable)

                String[] ids= diningTableIds.split('_')

                def diningTable= tDao.queryForId(ids[0])

                def orderNo= diningTable.tranFlowno// 当前对应的点单号

                def sDao= DaoManager.createDao(transConnSrc, MposSalesOrder)

                List salesOrders

    if (orderNo) {

                    salesOrders= sDao.queryBuilder()

                            .orderBy('id',true)

                            .where().eq('flowno', orderNo).and().ne("saleQty",new BigDecimal(0))

                            .query()

                }

                if (!salesOrders) {

                    salesOrders= []

                }

                def gson= createGson()

                def json= gson.toJson(salesOrders)

                output<< json

    output<< '\n'

                output.flush()

                def response= readLine(input)

                if (response) {

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                } else {

                    log.info"[${storeId}_${deviceId}]Client disconnected."

                    return

                }

                diningTable= tDao.queryForId(ids[1])

                orderNo= diningTable.tranFlowno// 当前对应的点单号

                sDao= DaoManager.createDao(transConnSrc, MposSalesOrder)

                salesOrders= []

                if (orderNo) {

                    salesOrders= sDao.queryBuilder()

                            .orderBy('id',true)

                            .where().eq('flowno', orderNo).and().ne("saleQty",new BigDecimal(0))

                            .query()

                }

                if (!salesOrders) {

                    salesOrders= []

                }

                json= gson.toJson(salesOrders)

                output<< json

    output<< '\n'

                output.flush()

                response= readLine(input)

                if (response) {

                    log.info"[${storeId}_${deviceId}]Client response: ${response}"

                } else {

                    log.info"[${storeId}_${deviceId}]Client disconnected."

                    return

                }

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId} ${diningTableIds}]getTransactionInfos failed", e

    output<< 'ng\n'

            }

    }

        static void putCombineTable(storeId, deviceId, OutputStream output, InputStream input) {

            try {

                String objectsInJSON= readLine(input)

                log.info"[${storeId}_${deviceId}]Receive: ${objectsInJSON}"

                def gson= createGson()

                Type collectionType= new TypeToken>() {}.getType()

                List diningTables= gson.fromJson(objectsInJSON, collectionType)

                String sourceTableCode= diningTables[0].deskNo

    String targetTableCode= diningTables[1].deskNo

    //            def connSrc = getDbConnection()

                def transConnSrc= getDbConnection(false)

                def dao= DaoManager.createDao(transConnSrc, MposDiningTable)

                def tdao= DaoManager.createDao(transConnSrc, MposSalesOrder)

                String sql= "select deskNo, tranFlowno from pos_deskInfo where deskNo = '${sourceTableCode}' or deskNo = '${targetTableCode}'"

                GenericRawResults rawResults= dao.queryRaw(sql)

                List results= rawResults.getResults()

                int targetTranFlowCount= 0

                String sourceFlowno= ''

                String targetFlowno= ''

                if (results) {

                    results.each{ String[] resultArray ->

    String deskNo= resultArray[0]

                        if (deskNo== sourceTableCode) {

                            sourceFlowno= resultArray[1]

                        } else {

                            targetFlowno= resultArray[1]

                            sql= "select COUNT(flowno) from pos_Tranflowhd where flowno = '${resultArray[1]}'"

                            GenericRawResults rawResults1= tdao.queryRaw(sql)

                            List results1= rawResults1.getResults()

                            if (results)

                                targetTranFlowCount= results1[0][0] as Integer

    }

    }

    }

                sql= "update pos_tranflowhd set flowno = '${targetFlowno}', itemseq = itemseq + ${targetTranFlowCount} where WarehouseID='${storeId}' and flowno = '${sourceFlowno}'"

                tdao.updateRaw(sql)

                diningTables.each{

                    dao.update it

    }

                def sdao= DaoManager.createDao(transConnSrc, MposDiffSalesOrder)

                List diffSalesOrderList= sdao.queryForEq("flowno", diningTables[1].tranFlowno)

                diffSalesOrderList*.roomNo= diningTables[1].roomNo

    diffSalesOrderList*.deskNo= diningTables[1].deskNo

    diffSalesOrderList*.deskName= diningTables[1].deskName

    int allQty= 0

                diffSalesOrderList.each{

                    it.roomNo= diningTables[1].roomNo

    it.deskNo= diningTables[1].deskNo

    it.deskName= diningTables[1].deskName

    it.message= "并桌  原${diningTables[0].deskName} "

                    allQty+= it.saleQty

    sdao.update(it)

                }

                //打印控菜单

                if (dbConf.kitchen.printAll== 'Y') {

                    try {

                        lock.lock()

                        diffSalesOrderList*.allQty= allQty

    if (diffSalesOrderList.size() > 0) {

                            PrintServer printServer= new PrintServer()

                            printServer.printSaleOrder(diffSalesOrderList)

                        }

                    } catch (Exception e) {

                        log.error(e)

                    } finally {

                        lock.unlock()

                    }

    }

                output<< 'ok\n'

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId} combine table failed", e

    output<< 'ng\n'

            }

    }

        static void putSplitTable(storeId, deviceId, OutputStream output, InputStream input) {

            try {

                String objectsInJSON= readLine(input)

                log.info"[${storeId}_${deviceId}]Receive: ${objectsInJSON}"

                def gson= createGson()

                Type collectionType= new TypeToken>() {}.getType()

                List diningTables= gson.fromJson(objectsInJSON, collectionType)

    //            def connSrc = getDbConnection()

                def transConnSrc= getDbConnection(false)

                def tDao= DaoManager.createDao(transConnSrc, MposDiningTable)

                def dDao= DaoManager.createDao(transConnSrc, MposSalesOrder)

                diningTables.each{ diningTable ->

    tDao.callBatchTasks{

                        String tranFlowno= diningTable.tranFlowno

    if (tranFlowno) {

                            def deleteBuilder= dDao.deleteBuilder()

                            deleteBuilder.where().eq('warehouseId', storeId).and().eq('flowno', tranFlowno)

                            int rows= deleteBuilder.delete()

                            if (rows> 0)

                                log.info"Delete existing $rows rows from pos_tranflowhd with warehouseId='$storeId' and flowno='$diningTable.tranFlowno'"

                        }

                        if (diningTable.salesOrders.size() > 0) {

                            if (!tranFlowno) {

                                tranFlowno= getNextOrderNumberOfDevice(transConnSrc, storeId, deviceId)

                                diningTable.tranFlowno= tranFlowno

    }

                            diningTable.salesOrders.each{ salesOrder ->

    salesOrder.id= 0

                                salesOrder.flowno= tranFlowno

    dDao.create salesOrder

    }

                        } else {

                            diningTable.tranFlowno= ''

                        }

                        tDao.update diningTable

    }

    }

                output<< 'ok\n'

            } catch (Exception e) {

                log.warn"[${storeId}_${deviceId} split table failed", e

    output<< 'ng\n'

            }

    }

        static void copy(storeId, deviceId, InputStream inputStream, OutputStream outputStream) {

            byte[] buffer= new byte[1024]

            int length

    while ((length= inputStream.read(buffer)) > 0) {

                outputStream.write(buffer,0, length)

            }

            log.info"[${storeId}_${deviceId}]Write... end"

            outputStream.flush()

        }

        static void copy(storeId, deviceId, InputStream inputStream, OutputStream outputStream, size) {

            byte[] buffer= new byte[1024]

            int length

    int lengthRead= 0

            while ((length= inputStream.read(buffer)) > 0) {

                outputStream.write(buffer,0, length)

                lengthRead+= length

    if (lengthRead>= size)

                    break;

    }

            log.info"[${storeId}_${deviceId}]Write... end"

            outputStream.flush()

        }

        /**

    * Read directory info from Groovy script: conf/db.properties.

    */

        static void getUploadDir2() {

            dbConf= new ConfigSlurper().parse(new File('conf/db.properties').toURI().toURL())

            uploadDir= dbConf.db.uploadDir ? dbConf.db.uploadDir :'inbox'

            log.info"uploadDir = ${uploadDir}"

            transDirInConf= dbConf.db.transDir ? dbConf.db.transDir :'trans'

            log.info"transDir = ${transDirInConf}"

        }

        /** Read database connection info from Groovy script:conf/db.properties, and create ORMLite connection source. */

        static ConnectionSource getDbConnection(boolean isMaster= true) {

            log.info("AppServer getDbConnection() isMaster = ${isMaster}")

            ConnectionSource db

    if (isMaster) {

                db= DBUtil.getMasterDbConnection()

            } else {

                db= DBUtil.getTransDbConnection()

            }

            dbType= DBUtil.dbType

    return db

    }

        /** Read database connection info from Groovy script: conf/db.properties, and create Groovy Sql object. */

        static Sql getGroovySql() {

            dbConf= new ConfigSlurper().parse(new File('conf/db.properties').toURI().toURL())

            dbType= (dbConf.db.url.contains('mysql')) ?'MySQL' :

    (dbConf.db.url.contains('sqlserver')) ?'SQLServer' :'Sybase'

            TABLE_PREFIX= (dbType== 'Sybase' ?'tab.' :'')

            Sql.newInstance(dbConf.db.url, dbConf.db.user, dbConf.db.password, dbConf.db.driverClass)

        }

        /** Load dining table state transition rules in STL (State Transition Language). */

        static void loadSTLMap() {

            stlMap.clear()

            dbConf= new ConfigSlurper().parse(new File('conf/db.properties').toURI().toURL())

            if (dbConf.stl) {

                def stl= dbConf.stl ?:'0空桌 -> 1点餐中 <-> 2已点餐 <-> 3结账中 -> 4已结账 & 清桌中 -> 0空桌'

                def tokens= stl.split(/(?<=(<->))|(?=(<->))/).collect{

                    (it== '<->') ? it : it.split(/(?<=(->))|(?=(->))/)

                }.flatten()*.replaceAll(/^\s*/,'')*.trim()

                tokens.eachWithIndex{ token, idx ->

    if (token== '->' || token== '<->') {

                        def left= tokens[idx- 1][0]

                        def right= tokens[idx+ 1][0]

                        stlMap[left] = (stlMap[left] ?:'') + right

    if (token== '<->')

                            stlMap[right] = (stlMap[right] ?:'') + left

    }

    }

    }

            //println stlMap

        }

        //获取当前门店营业日期

        static String getAccDate(String storeId) {

            ConnectionSource db= getDbConnection(false)

            Dao dao= DaoManager.createDao(db, MposTransaction)

            GenericRawResults rawResults1= dao.queryRaw("select faccdate from calendar where fOrgNo = ${storeId}")

            List results1= rawResults1.getResults()

            Date accdate= null

            if (results1) {

                String str= results1[0][0]

                if (str.length() > 10) {

                    return str.substring(0,10)

                }

                accdate= new Date()

            }

            if (!accdate) {

                accdate= new Date()

            }

            SimpleDateFormat format= new SimpleDateFormat("yyyy-MM-dd")

            return format.format(accdate)

        }

        /** Start method of Apache Commons Procrun. */

        static void start(String[] args) {

            main(null)

        }

        /** Stop method of Apache Commons Procrun. */

        static void stop(String[] args) {

            System.exit0

        }

        static void init() {

            try {

                ConnectionSource db= getDbConnection(false)

                log.info("init  getDbConnection .")

                // ['Tc_Shift', 'MposShift', '交班表'],

                TableUtils.createTableIfNotExists(db, MposShift.class)

                //['pos_tranflowhd', 'MposSalesOrder', '点单表'],

                TableUtils.createTableIfNotExists(db, MposSalesOrder.class)

                //厨打

                TableUtils.createTableIfNotExists(db, MposDiffSalesOrder.class)

                //['pos_tranhead', 'MposTransaction', '交易主表'],

                TableUtils.createTableIfNotExists(db, MposTransaction.class)

                //['pos_tranflow', 'MposLineItem', '交易明细'],

                TableUtils.createTableIfNotExists(db, MposLineItem.class)

                //['pos_tranpay', 'MposTransactionTender', '交易支付'],

                TableUtils.createTableIfNotExists(db, MposTransactionTender.class)

                //第三方支付明细

                TableUtils.createTableIfNotExists(db, MposO2oPayDtl.class)

                //礼券明细

                TableUtils.createTableIfNotExists(db, MposTicketDtl.class)

                //外卖平台交易

                TableUtils.createTableIfNotExists(db, MposTakeOutTransaction.class)

                //外卖平台交易明细

                TableUtils.createTableIfNotExists(db, MposTakeOutTranflow.class)

                //银行支付明细

                TableUtils.createTableIfNotExists(db, MposCardDtl.class)

                TableUtils.createTableIfNotExists(db, MposDiningArea.class)

                TableUtils.createTableIfNotExists(db, MposDiningTable.class)

                TableUtils.createTableIfNotExists(db, MposShiftReport.class)

                TableUtils.createTableIfNotExists(db, MposTrantaste.class)

                log.info("Tables was created.")

                deleteHistoryData(dbConf.TransReserved ?:2)

                databaseCheck(db)

            } catch (Exception e) {

                log.error('AppServer', e)

            }

    }

        static void deleteHistoryData(int month) {

            ConnectionSource db= getDbConnection(false)

            SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd")

            Calendar dueDate= Calendar.getInstance()

            dueDate.setTime(new Date())

            dueDate.add(Calendar.MONTH,-month)

            String dateStr= formatter.format(dueDate.getTime())

            //删除礼券支付明细

            log.info("Remove pos_TicketDtl before " + dateStr)

            def tkDao= DaoManager.createDao(db, MposTicketDtl)

            DeleteBuilder db5= tkDao.deleteBuilder()

            db5.where().lt("Accdate", dateStr).and().ne('Accdate','1970-01-01')

            db5.delete()

            //删除第三方式支付明细

            log.info("Remove pos_o2opaydtl before " + dateStr)

            def oDao= DaoManager.createDao(db, MposO2oPayDtl)

            DeleteBuilder db4= oDao.deleteBuilder()

            db4.where().lt("Accdate", dateStr).and().ne('Accdate','1970-01-01')

            db4.delete()

            //删除银联支付明细

            log.info("Remove pos_carddtl before " + dateStr)

            def cDao= DaoManager.createDao(db, MposCardDtl)

            DeleteBuilder db10= cDao.deleteBuilder()

            db10.where().lt("Accdate", dateStr).and().ne('Accdate','1970-01-01')

            db10.delete()

            //删除明细

            log.info("Remove pos_tranflow before " + dateStr)

            def dDao= DaoManager.createDao(db, MposLineItem)

            DeleteBuilder db2= dDao.deleteBuilder()

            db2.where().lt("AccDate", dateStr).and().ne('Accdate','1970-01-01')

            db2.delete()

            //删除点餐明细

            log.info("Remove pos_tranflowhd before " + dateStr)

            def soDao= DaoManager.createDao(db, MposSalesOrder)

            DeleteBuilder db8= soDao.deleteBuilder()

            db8.where().lt("operDate", dueDate.getTime())

            db8.delete()

            //删除厨打明细

            log.info("Remove pos_tranflowhd before " + dateStr)

            def dsDao= DaoManager.createDao(db, MposDiffSalesOrder)

            DeleteBuilder db9= dsDao.deleteBuilder()

            db9.where().lt("operDate", dueDate.getTime())

            db9.delete()

            //删除支付明细

            log.info("Remove pos_tranpay before " + dateStr)

            def tDao= DaoManager.createDao(db, MposTransactionTender)

            DeleteBuilder db3= tDao.deleteBuilder()

            db3.where().lt("Accdate", dateStr).and().ne('Accdate','1970-01-01')

            db3.delete()

            //删除头表

            log.info("Remove pos_tranhead before " + dateStr)

            def hDao= DaoManager.createDao(db, MposTransaction)

            DeleteBuilder db1= hDao.deleteBuilder()

            db1.where().lt("AccDate", dateStr).and().ne('Accdate','1970-01-01')

            db1.delete()

            //删除交班支付明细表

            log.info("Remove Tc_Shift before " + dateStr)

            def psDao= DaoManager.createDao(db, MposShiftReport)

            DeleteBuilder db7= psDao.deleteBuilder()

            db7.where().lt("Accdate", dateStr).and().ne('Accdate','1970-01-01')

            db7.delete()

            //删除交班头表

            log.info("Remove Tc_Shift before " + dateStr)

            def sDao= DaoManager.createDao(db, MposShift)

            DeleteBuilder db6= sDao.deleteBuilder()

            db6.where().lt("fAccDate", dueDate.getTime()).and().ne('fAccdate', getInitialDate())

            db6.delete()

        }

        static void version1_4_9(DatabaseConnection conn) {

            try {

                conn.executeStatement('''\

                        select elecDiscountAmt from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add elecDiscountAmt decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select elecIptNum from pos_TicketDtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_TicketDtl add elecIptNum VARCHAR(20); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select ticketType from pos_TicketDtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_TicketDtl add ticketType VARCHAR(20); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select type from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add type VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select AgeLevel from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add AgeLevel int; ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select returnPartAmount from pos_carddtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_carddtl add returnPartAmount decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select taste_nos from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add taste_nos VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select memo from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add memo VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select taste_nos from pos_TranflowhdPr''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_TranflowhdPr add taste_nos VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select comment from pos_TranflowhdPr''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_TranflowhdPr add comment VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select taste_nos from pos_tranflowhd''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflowhd add taste_nos VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select comment from pos_tranflowhd''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflowhd add comment VARCHAR(100); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select pcouponAmount from pos_o2opaydtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_o2opaydtl add pcouponAmount decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select discountAcc from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add discountAcc VARCHAR(20); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select discountType from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add discountType VARCHAR(10); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select discountNum from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add discountNum VARCHAR(20); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select delivery_type from takeOut_postranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranhead add delivery_type int; ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select delivery_party from takeOut_postranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranhead add delivery_party VARCHAR(50); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select package_amount from takeOut_postranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranhead add package_amount int; ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select GrosalAMT from takeOut_postranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranhead add GrosalAMT decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select foodType from takeOut_postranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranflow add foodType VARCHAR(10); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select discAmt from takeOut_postranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table takeOut_postranflow add discAmt decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select tranState from pos_o2opaydtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_o2opaydtl add tranState varchar(5); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select origamt from pos_carddtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_carddtl add origamt decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select mcouponamount from pos_carddtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_carddtl add mcouponamount decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select pcouponAmount from pos_carddtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_carddtl add pcouponAmount decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select point from pos_carddtl''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_carddtl add point decimal(12, 2); ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

    }

        static void version1_4_2(DatabaseConnection conn) {

            try {

                conn.executeStatement('''\

                        select isEInvoice from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add isEInvoice VARCHAR(10) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select custNumber from pos_tranflowhd''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflow add custNumber int default 1 ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select custNumber from pos_TranflowhdPr''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_TranflowhdPr add custNumber int default 1 ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select custNumber from pos_Tranflowhd''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_Tranflowhd add custNumber int default 1 ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

    }

        static void version1_4_1(DatabaseConnection conn) {

            try {

                conn.executeStatement('''\

                        select EInvoiceContent from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add EInvoiceContent varchar(200) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select tariffNo from pos_tranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflow add tariffNo varchar(50) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select tariffName from pos_tranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflow add tariffName varchar(100) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select fClassStNo from pos_tranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflow add fClassStNo varchar(50) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select EInvoiceFlowNo from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add EInvoiceFlowNo varchar(20) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select EInvoiceFPDM from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add EInvoiceFPDM varchar(20) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select EInvoiceFPHM from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add EInvoiceFPHM varchar(20) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select EInvoicePDFURL from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add EInvoicePDFURL varchar(200) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

    }

        static void version1_4_0(DatabaseConnection conn) {

            try {

                conn.executeStatement('''\

                        select platformType from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add platformType varchar(20) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select jshopFlowno from pos_tranhead''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranhead add jshopFlowno varchar(50) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select TaxId from pos_tranflow''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table pos_tranflow add TaxId decimal(12, 2) ''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select pointChange from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table Tc_Shift add pointChange int''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select point from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table Tc_Shift add point int''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select RefillAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add RefillAmt decimal(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select ServiceAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add ServiceAmt decimal(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select RefundAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add RefundAmt RefundAmt(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select OverAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add OverAmt RefundAmt(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select inAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add inAmt RefundAmt(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

            try {

                conn.executeStatement('''\

                        select outAmt from tc_shift''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            } catch (Exception e) {

                conn.executeStatement('''\

                        alter table tc_shift add outAmt outAmt(12, 2)''', DatabaseConnection.DEFAULT_RESULT_FLAGS)

            }

    }

        static databaseCheck(ConnectionSource sqlserverConn) {

            DatabaseConnection conn

    try {

                conn= sqlserverConn.getReadWriteConnection()

                version1_4_0(conn)

                version1_4_1(conn)

                version1_4_2(conn)

                version1_4_9(conn)

            } catch (Exception e) {

                log.error('Failed ', e)

            } finally {

                if (conn)

                    sqlserverConn.releaseConnection conn

    }

    }

        static Date getInitialDate() {

            Date initDate= new Date(0);

    int timeOffset= 0;

    TimeZone timeZone= Calendar.getInstance().getTimeZone();

    timeOffset= timeOffset- timeZone.getRawOffset();

    initDate.setTime(timeOffset);

    return initDate;

    }

        /**

    * Entry point of App Server.

    */

        static main(_) {

            // Help to find log4j.properties

            PropertyConfigurator.configure'conf/log4j.properties'

            log.info("AppServer is starting")

            // Remove log files one month ago

            Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({

                def now= new Date()

                def dueDay= String.format('%1$tY-%1$tm-%1$td', now- 30)

                ('log' as File).eachFile{ logFile ->

    def extension= logFile.name.split(/\./)[-1]

                    if (extension==~ /2\d\d\d-\d\d-\d\d/ && extension< dueDay)

                        logFile.delete()

                }

            },0,1, TimeUnit.HOURS)

            //半夜四点重启系统

          Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({

              def now= new Date()

              log.info("system exit")

              int hour= 4

              try {

                  if (dbConf.rebootHour!= 4) {

                      hour= Integer.valueOf(dbConf.rebootHour).intValue()

                  }

              } catch (Exception e){}

              if (now.hours== hour) {

                  log.info("system exit ${now.hours}")

                  System.exit(0)

              }

          },30,40, TimeUnit.MINUTES)

            try {

                Thread.sleep(5000)

            } catch (Exception e){}

            loadSTLMap()

            //判断是否启动厨打

            if (dbConf.kitchen.print!= 'N') {

    //            PrintServer.lock = lock

                PrintServer.main(null)

            }

            APP_SERVER_PORT= dbConf.serverPort ? Integer.valueOf(dbConf.serverPort) : APP_SERVER_PORT

    serverType= dbConf.serverType

    try {

                log.info("PushServer start")

                pushServer= new PushServer()

            } catch (Exception e) {

                log.error("AppServer PushServer error", e)

            }

            try {

                if (serverType== 'SC') {

                    log.info("AppServer init()")

                    init()

                    if (dbConf.runType== '1')

                        new Thread(new Runnable() {

                            @Override

    void run() {

                                AppClient.main(['true', VERSION] as String[])

                            }

                        }).start()

                } else if (serverType== 'HQ') {

                    //自动生成主档

                    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({

                        def now= new Date()

                        log.info("master copy ")

                        int hour= 5

                        try {

                            if (dbConf.masterCopyHour!= 5) {

                                hour= (Integer.valueOf(dbConf.masterCopyHour).intValue())

                            }

                        } catch (Exception e){}

                        if (now.hours== hour) {

                            log.info("master copy ${now.hours}")

                            MposMasterCopy.main("001_")

                        }

                    },0,40, TimeUnit.MINUTES)

                    //HQ的通讯server启动时将非码client启动

                    if (dbConf.runFmClient!= 'N') {

                        try {

                            log.info("./FMClient/fmstart.bat")

                            Runtime.runtime.exec("./FMClient/fmstart.bat")

                        } catch (Exception e) {}

    }

    }

            } catch (Exception e) {

                log.error("AppServer process serverType", e)

            }

            // Start server loop

            for (; ;) {

                try {

                    serverLoop()

                } catch (BindException e) {

                    log.warn'main> Server close', e

    System.exit(0)

                    return

                } catch (Exception e) {

                    log.warn'main> Server failed', e

    if (e.getMessage().contains('maximum connections reached')) {

                        System.exit(1)

                    }

                } finally {

                    try {

                        server?.close()

                        server= null

                        sleep2000

                    } catch (Exception ignore) {

    }

    }

    }

    }

    }






    APPServer32类

    package hyi.pos.appserver.server;

    import org.boris.winrun4j.AbstractService;

    import org.boris.winrun4j.EventLog;

    import org.boris.winrun4j.ServiceException;

    import java.io.File;

    /**

    * App server starter. It'll run as a Windows service.

    *

    * This class will be packaged as AppServerStarter.jar, and put it to SC's c:\AppServer directory.

    *

    * @author Bruce You

    * @since 2013 Mar.

    */

    public class AppServerStarter32 extends AbstractService {

        private static final String TAG = "AppServerStarter";

        //private static final String HOME_DIR = ".";

    //创建一个进程

        private Process appServerProcess;

        @Override

        public int serviceMain(String[] args) throws ServiceException {

            for (;;) {

                try {

                    // Respawn AppServer.exe --

                    ProcessBuilder pb = new ProcessBuilder(args.length > 0 ? args[0] : "AppServer32.exe");

                    //pb.directory(new File(HOME_DIR));

                    appServerProcess = pb.start();

                    EventLog.report(TAG, EventLog.INFORMATION, "Start " + (args.length > 0 ? args[0] : "AppServer32.exe"));

                    appServerProcess.waitFor();

                    appServerProcess = null;

                } catch (Exception e) {

                    EventLog.report(TAG, EventLog.WARNING, e.getMessage());

                }

    }

    }

        @Override

        public int serviceRequest(int control) throws ServiceException {

            super.serviceRequest(control);

            switch (control) {

                case SERVICE_CONTROL_STOP:

                case SERVICE_CONTROL_SHUTDOWN:

                    if (appServerProcess != null)

                        appServerProcess.destroy();

                    System.exit(0);

            }

            return 0;

        }

    }




    AppServer64类:

    package hyi.pos.appserver.server;

    import org.boris.winrun4j.AbstractService;

    import org.boris.winrun4j.EventLog;

    import org.boris.winrun4j.ServiceException;

    import java.io.File;

    /**

    * App server starter. It'll run as a Windows service.

    *

    * This class will be packaged as AppServerStarter.jar, and put it to SC's c:\AppServer directory.

    *

    * @author Bruce You

    * @since 2013 Mar.

    */

    public class AppServerStarter64 extends AbstractService {

        private static final String TAG = "AppServerStarter";

    //    private static final String HOME_DIR = ".";

        private Process appServerProcess;

        @Override

        public int serviceMain(String[] args) throws ServiceException {

            for (;;) {

                try {

                    // Respawn AppServer.exe --

    //进程建立

                    ProcessBuilder pb = new ProcessBuilder(args.length > 0 ? args[0] : "AppServer64.exe");

    //                pb.directory(new File(HOME_DIR));

                    appServerProcess = pb.start();

                    EventLog.report(TAG, EventLog.INFORMATION, "Start " + (args.length > 0 ? args[0] : "AppServer64.exe"));

                    appServerProcess.waitFor();

                    appServerProcess = null;

                } catch (Exception e) {

                    EventLog.report(TAG, EventLog.WARNING, e.getMessage());

                }

    }

    }

        @Override

        public int serviceRequest(int control) throws ServiceException {

            super.serviceRequest(control);

            switch (control) {

                case SERVICE_CONTROL_STOP:

                case SERVICE_CONTROL_SHUTDOWN:

                    if (appServerProcess != null)

                        appServerProcess.destroy();

                    System.exit(0);

            }

            return 0;

        }

    }


    官网解释:



    最后编辑于
    ©著作权归作者所有,转载或内容合作请联系作者
    • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
      沈念sama阅读 194,088评论 5 459
    • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
      沈念sama阅读 81,715评论 2 371
    • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
      开封第一讲书人阅读 141,361评论 0 319
    • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
      开封第一讲书人阅读 52,099评论 1 263
    • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
      茶点故事阅读 60,987评论 4 355
    • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
      开封第一讲书人阅读 46,063评论 1 272
    • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
      沈念sama阅读 36,486评论 3 381
    • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
      开封第一讲书人阅读 35,175评论 0 253
    • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
      沈念sama阅读 39,440评论 1 290
    • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
      茶点故事阅读 34,518评论 2 309
    • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
      茶点故事阅读 36,305评论 1 326
    • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
      沈念sama阅读 32,190评论 3 312
    • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
      茶点故事阅读 37,550评论 3 298
    • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
      开封第一讲书人阅读 28,880评论 0 17
    • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
      开封第一讲书人阅读 30,152评论 1 250
    • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
      沈念sama阅读 41,451评论 2 341
    • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
      茶点故事阅读 40,637评论 2 335

    推荐阅读更多精彩内容

    • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
      卡卡罗2017阅读 134,490评论 18 139
    • ```java /* * Copyright (C) 2006 The Android Open Source P...
      mrganer阅读 1,121评论 0 50
    • 多态 任何域的访问操作都将有编译器解析,如果某个方法是静态的,它的行为就不具有多态性 java默认对象的销毁顺序与...
      yueyue_projects阅读 920评论 0 1
    • JAVA面试题 1、作用域public,private,protected,以及不写时的区别答:区别如下:作用域 ...
      JA尐白阅读 1,138评论 1 0
    • 小编月光 笙歌间错华筵启。 喜新春新岁。 菜传纤手青丝细。 和气入、东风里。 幡儿胜儿都姑媂。 戴得更忔戏。 愿新...
      灵感工作室阅读 1,341评论 0 1