def onSchedule(self, evt):
        self.scheduledInput = self.selectedScheduleInput
        self.startDateInput.SetValue(TimeUtil.getMonday(self.startDateInput.GetValue()))
        self.endDateInput.SetValue(TimeUtil.getSunday(self.endDateInput.GetValue()))
        self.scheduledStartDate = self.startDateInput.GetValue()
        if not self.checkInput():
            return

        self.resultList = list()
        for input in self.scheduledInput:
            scheduledWorkers = input[0]
            scheduledGroup = input[1]
            # 现在将工作和休息互换,算法不变
            s = Scheduler(workers=list(range(len(scheduledWorkers))),
                          dailyRequiredWorkerNum=len(scheduledWorkers) - int(scheduledGroup.workLoad),
                          maxRestDay=self.maxWorkDaysInput.GetValue(),
                          maxWorkDay=self.maxRestDaysInput.GetValue(),
                          isShuffle=True)
            targetDays = TimeUtil.getDayLength(self.startDateInput.GetValue(), self.endDateInput.GetValue())
            scheduleResult = s.schedule(int(targetDays))
            if scheduleResult.message.strip() != '':
                wx.MessageBox(scheduledGroup.groupName + ": " + scheduleResult.message)

            self.resultList.append([scheduleResult.restCalendar, scheduledWorkers, scheduledGroup])

        self.displayScheduleResult(self.resultList, self.scheduledStartDate)
        self.exportBtn.Enable(True)
        self.saveBtn.Enable(True)
        self.selectedScheduleInput = list()
    def onExport(self, evt):
        dialog = wx.FileDialog(self, u"选择要导出的文件位置", os.getcwd(), style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
                               wildcard="*.csv")
        if dialog.ShowModal() == wx.ID_OK:
            filePath = dialog.GetPath()
            if filePath:
                try:
                    personalWorkDayDict = self.exportData[0]
                    dailyAttendenceList = self.exportData[1]
                    personalWorkDayLengthList = self.exportData[2]
                    startDate = self.exportData[3]

                    firstLine = u'员工名,班组名'
                    totalWeekNum = int(len(dailyAttendenceList) / 7)
                    for totalWeekNum in range(1, totalWeekNum + 1):
                        dateStr = u',"第 ' + str(totalWeekNum) + u' 周\n'
                        endDate = TimeUtil.getFormatedDate(startDate, 6)
                        dateStr += (startDate + ' -- ' + endDate + '"')
                        firstLine += dateStr
                        startDate = TimeUtil.getFormatedDate(endDate, 1)

                    lines = [firstLine]

                    for item in personalWorkDayDict:
                        wokerName = item[0]
                        groupName = item[1]
                        workDayList = item[2]
                        lines.append(wokerName + ',' + groupName + u',' + u','.join(
                            list(map(lambda week: ' '.join(list(map(str, week))), workDayList))))

                    lines.append('\n')
                    lines.append(u'员工名,班组名,总天数,总工时(小时)')
                    # 工时
                    for i in range(len(personalWorkDayLengthList)):
                        lines.append(','.join(personalWorkDayLengthList[i]))

                    lines.append('\n')
                    lines.append(u'日期,出勤员工')
                    groupInfo = ',' + ''.join(list(map(lambda x: x[1].groupName + ',' * int(x[1].workLoad), dailyAttendenceList[0][1])))

                    innerLines = list()
                    for dailyAttendence in dailyAttendenceList:
                        date = dailyAttendence[0]
                        groupAttendenceList = dailyAttendence[1]
                        attendenceStr = date
                        for groupAttendence in groupAttendenceList:
                            attendence = groupAttendence[0]
                            attendenceStr += ',' + attendence
                        innerLines.append(attendenceStr)
                    lines.append(groupInfo)
                    lines.extend(innerLines)

                    FileUtil.writeAll(filePath, lines)
                    wx.MessageBox(u'成功导出到文件', filePath)
                except Exception as e:
                    wx.MessageBox(u'导出失败,原因为: ' + str(e))
        dialog.Destroy()
 def OnEnterDate(self, evt):
     if TimeUtil.isValidDate(self.startDateInput.GetValue()) \
             and TimeUtil.isValidDate(self.endDateInput.GetValue()) \
             and TimeUtil.getDayLength(self.startDateInput.GetValue(), self.endDateInput.GetValue()) > 0:
         self.warnMsg.Hide()
         self.scheduleBtn.Enable(True)
     else:
         self.warnMsg.Show()
         # re-layout
         self.vBox.Layout()
         self.scheduleBtn.Enable(False)
    def onFileRead(self, filePath):
        if filePath:
            try:
                lines = DailyDataDAL.readAll(filePath)
                dailyData = DailyDataDAL.parse(lines, TimeUtil.getToday())
                DailyDataDAL.persistAll(dailyData)

                newDailyData = DailyDataDAL.fetchAllByDate(TimeUtil.getToday())
                self.buyerPanel.updateGrid(newDailyData.toStringList())

                wx.MessageBox("导入数据成功", "导入数据", style=wx.OK | wx.ICON_EXCLAMATION)
            except:
                wx.MessageBox("导入数据失败,请检测数据格式", "导入数据", style=wx.OK | wx.ICON_EXCLAMATION)
    def setupDateInput(self):
        sizer = wx.GridBagSizer(4, 4)
        dateText = wx.StaticText(self, label='日期')
        sizer.Add(dateText, pos=(0, 0), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.dateInput = wx.TextCtrl(self, value=TimeUtil.getToday(), style=wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_TEXT_ENTER, self.onSearchDate, self.dateInput)
        sizer.Add(self.dateInput, pos=(0, 1),
                  flag=wx.TOP | wx.LEFT, border=12)

        self.calculateButton = wx.Button(self, label='计算一天战况', size=(100, 30))
        sizer.Add(self.calculateButton, pos=(0, 2), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=12)
        self.calculateButton.Enable(True)
        self.Bind(wx.EVT_TEXT, self.OnEnter, self.dateInput)
        self.Bind(wx.EVT_BUTTON, self.onSearchDate, self.calculateButton)

        self.warnMsg = wx.StaticText(self, label='非法日期,请重新输入')
        self.warnMsg.SetForegroundColour('red')
        sizer.Add(self.warnMsg, pos=(0, 3), flag=wx.TOP | wx.LEFT, border=15)
        self.warnMsg.Hide()

        scoreText = wx.StaticText(self, label='盈亏')
        sizer.Add(scoreText, pos=(1, 0), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.score = wx.StaticText(self, label='0')
        sizer.Add(self.score, pos=(1, 1), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.vBox.Add(sizer, flag=wx.ALIGN_TOP, border=10)
    def displayTodayData(self):
        sizer = wx.GridBagSizer(4, 4)
        today = TimeUtil.getToday()
        # Load buyer data
        dailyData = DailyDataDAL.fetchAllByDate(today)

        # set data into data grid
        self.data = UserGridData()
        self.data.InsertRows(dailyData.toStringList())
        self.grid = wx.grid.Grid(self, size=(500, 300))
        self.grid.SetTable(self.data)
        self.grid.AutoSize()
        sizer.Add(self.grid, pos=(1, 1), span=(3, 3), flag=wx.EXPAND | wx.TOP, border=5)

        searchText = wx.StaticText(self, label='名称')
        sizer.Add(searchText, pos=(4, 1), flag=wx.EXPAND, border=5)

        self.searchInput = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_TEXT_ENTER, self.onSearchName, self.searchInput)
        sizer.Add(self.searchInput, pos=(4, 2),
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)


        self.searchBtn = wx.Button(self, label='查找', size=(100, 20))
        sizer.Add(self.searchBtn, pos=(4, 3))
        self.searchBtn.Enable(True)
        self.Bind(wx.EVT_BUTTON, self.onSearchName, self.searchBtn)

        sizer.AddGrowableRow(1)
        self.vBox.Add(sizer, wx.ALIGN_BOTTOM, 10)
    def displayScheduleResult(self, resultList, startDate):
        personalWorkDayDict = list()
        personalWorkDayLengthList = list()
        dailyAttendenceDict = dict()
        for result in resultList:
            calendar = result[0]
            workers = result[1]
            group = result[2]
            try:
                workdayDict = Scheduler.getWorkDayForEachWorker(calendar, workers)
                for (workIndex, workDayList) in workdayDict.items():
                    workDayList = list(map(int, workDayList))
                    workDayList.sort()
                    weeklyWorkDayList = list()
                    week = 1
                    startIndex = 0
                    for dateIndex in range(len(workDayList)):
                        if int(workDayList[dateIndex]) > week * 7:
                            weeklyWorkDayList.append(
                                list(
                                    map(lambda date: date % 7 if date % 7 != 0 else 7,
                                        workDayList[startIndex: dateIndex])))
                            startIndex = dateIndex
                            week += 1
                    if startIndex < len(workDayList):
                        weeklyWorkDayList.append(
                            list(map(lambda date: date % 7 if date % 7 != 0 else 7,
                                     workDayList[startIndex: len(workDayList)])))
                    personalWorkDayDict.append([workers[workIndex], group.groupName, weeklyWorkDayList])

                personalTotalWorkDay = Scheduler.calculateWorkDayPerWorker(calendar)
                for i in range(len(workers)):
                    personalWorkDayLengthList.append(
                        [workers[i], group.groupName, str(personalTotalWorkDay.get(i, 0)),
                         str(personalTotalWorkDay.get(i, 0) * int(group.workHour))])
                # # 添加平均数行
                # avgWorkDayNum = math.ceil(float(len(calendar.keys())) * int(
                #     group.workLoad) / len(
                #     workers))
                # avgWorkHour = avgWorkDayNum * int(group.workHour)
                # workDayData.append([u'平均出勤天数', str(avgWorkDayNum), str(avgWorkHour)])

                for keyValuePair in sorted(calendar.items(), key=lambda d: int(d[0])):
                    currentDate = TimeUtil.getFormatedDate(startDate, int(keyValuePair[0]) - 1)
                    currentDateArrange = dailyAttendenceDict.get(currentDate, list())

                    currentDateArrange.append(
                        [",   ".join(map(str, map(lambda index: workers[index], keyValuePair[1]))), group])
                    dailyAttendenceDict[currentDate] = currentDateArrange

            except Exception as e:
                wx.MessageBox(u'出错啦: ' + str(e))

        # 按日期排序
        dailyAttendenceList = sorted(dailyAttendenceDict.items(), key=lambda d: d[0])
        self.exportData = [personalWorkDayDict, dailyAttendenceList, personalWorkDayLengthList, startDate]
        self.updateGrid(personalWorkDayLengthList)
        self.updateGrid1(personalWorkDayDict, startDate)
        self.updateGrid2(dailyAttendenceList)
 def OnEnter(self, evt):
     if TimeUtil.isValidDate(self.dateInput.GetValue()):
         self.warnMsg.Hide()
         self.calculateButton.Enable(True)
     else:
         self.warnMsg.Show()
         # re-layout
         self.vBox.Layout()
         self.calculateButton.Enable(False)
    def updateGrid1(self, rows, startDate):
        self.grid1.ClearGrid()
        currentRowNum = self.grid1.GetNumberRows()
        if currentRowNum < len(rows):
            self.grid1.AppendRows(numRows=(len(rows) - currentRowNum))
        elif currentRowNum > len(rows):
            self.grid1.DeleteRows(numRows=(currentRowNum - len(rows)))

        totalWeekNum = len(rows[0][2]) if len(rows) > 0 else 0
        currentColNum = self.grid1.GetNumberCols() - 2
        if currentColNum < totalWeekNum:
            self.grid1.AppendCols(numCols=(totalWeekNum - currentColNum))
        elif currentColNum > totalWeekNum:
            self.grid1.DeleteCols(numCols=(currentColNum - totalWeekNum))

        for totalWeekNum in range(1, totalWeekNum + 1):
            dateStr = u'第 ' + str(totalWeekNum) + u' 周\n'
            endDate = TimeUtil.getFormatedDate(startDate, 6)
            dateStr += (startDate + ' -- ' + endDate)
            self.grid1.SetColLabelValue(totalWeekNum + 1, dateStr)
            startDate = TimeUtil.getFormatedDate(endDate, 1)

        rowNum = 0
        previousGroupName = ''
        colorCnt = 0
        for item in rows:
            wokerName = item[0]
            groupName = item[1]
            workDayList = item[2]
            if groupName != previousGroupName:
                colorCnt += 1
                previousGroupName = groupName
            self.grid1.SetCellValue(rowNum, 0, wokerName)
            self.grid1.SetCellValue(rowNum, 1, groupName)
            self.grid1.SetCellBackgroundColour(rowNum, 0, self.colorList[colorCnt % 2])
            self.grid1.SetCellBackgroundColour(rowNum, 1, self.colorList[colorCnt % 2])
            for weekNum in range(len(workDayList)):
                self.grid1.SetCellValue(rowNum, weekNum + 2, ',  '.join(list(map(str, workDayList[weekNum]))))
                self.grid1.SetCellBackgroundColour(rowNum, weekNum + 2, self.colorList[colorCnt % 2])

            rowNum += 1
        self.grid1.AutoSize()
        self.vBox.Layout()
    def __init__(self, parent):
        scrolled.ScrolledPanel.__init__(self, parent)

        self.selectedScheduleInput = list()
        self.scheduledInput = list()
        self.scheduledStartDate = TimeUtil.getToday()
        self.exportData = list()
        self.displayWeeklyReport = True

        self.initUI()
        self.Show(True)
    def validate():
        if Constants.LICENSE_PURCHASED:
            return True

        conn = sqlite3.connect(Constants.DATABASE_ROOT_PATH +
                               LicenseValidateUtil.LICENSE_TABLE_NAME + '.db')
        c = conn.cursor()

        c.execute("CREATE TABLE IF NOT EXISTS " + LicenseValidateUtil.LICENSE_TABLE_NAME +
                  "(startDate VARCHAR[10], version VARCHAR[10])")
        c.execute("SELECT startDate FROM " + LicenseValidateUtil.LICENSE_TABLE_NAME + " WHERE version=" + Constants.APPLICATION_VERSION)
        startDate = c.fetchone()
        if startDate == None:
            c.execute("INSERT INTO " + LicenseValidateUtil.LICENSE_TABLE_NAME +
                      " VALUES ('" + TimeUtil.getToday() + "','" + Constants.APPLICATION_VERSION + "')")
            conn.commit()
            conn.close()
            return True
        else:
            conn.close()
            return TimeUtil.getDayLength(startDate[0], TimeUtil.getToday()) < Constants.MAX_FREE_TRIAL_DAY
    def setupDateInput(self):

        optionSizer = wx.GridBagSizer(4, 4)
        optionOuterSizer = wx.StaticBoxSizer(wx.HORIZONTAL, self, label=u'选项')

        userGroupText = wx.StaticText(self, label=u'排班班组')
        optionSizer.Add(userGroupText, pos=(0, 0), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)
        self.userGroupDropDown = wx.ListBox(self, style=wx.LB_MULTIPLE, choices=self.loadGroupList(), size=(100, 50))
        self.userGroupDropDown.Bind(wx.EVT_LISTBOX, self.onSelection)
        optionSizer.Add(self.userGroupDropDown, pos=(0, 1), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        minWorkDays = wx.StaticText(self, label=u'最大连续休息天数')
        optionSizer.Add(minWorkDays, pos=(1, 0), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.maxRestDaysInput = wx.TextCtrl(self, value='3', style=wx.TE_PROCESS_ENTER)
        optionSizer.Add(self.maxRestDaysInput, pos=(1, 1),
                        flag=wx.TOP | wx.LEFT, border=12)

        maxWorkDaysText = wx.StaticText(self, label=u'最大连续工作天数')
        optionSizer.Add(maxWorkDaysText, pos=(1, 2), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.maxWorkDaysInput = wx.TextCtrl(self, value='6', style=wx.TE_PROCESS_ENTER)
        optionSizer.Add(self.maxWorkDaysInput, pos=(1, 3),
                        flag=wx.TOP | wx.LEFT, border=12)

        startDate = wx.StaticText(self, label=u'开始日期')
        optionSizer.Add(startDate, pos=(2, 0), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.startDateInput = wx.TextCtrl(self, value=TimeUtil.getMonday(TimeUtil.getToday()),
                                          style=wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_TEXT, self.OnEnterDate, self.startDateInput)
        optionSizer.Add(self.startDateInput, pos=(2, 1),
                        flag=wx.TOP | wx.LEFT, border=12)

        endDate = wx.StaticText(self, label=u'结束日期')
        optionSizer.Add(endDate, pos=(2, 2), flag=wx.EXPAND | wx.TOP | wx.LEFT, border=15)

        self.endDateInput = wx.TextCtrl(self,
                                        value=TimeUtil.getSunday(
                                            TimeUtil.getFormatedDate(self.startDateInput.GetValue(), 55)),
                                        style=wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_TEXT, self.OnEnterDate, self.endDateInput)
        optionSizer.Add(self.endDateInput, pos=(2, 3),
                        flag=wx.TOP | wx.LEFT, border=12)

        blankMsg = wx.StaticText(self, label=u' ')
        optionSizer.Add(blankMsg, pos=(3, 0), flag=wx.TOP | wx.LEFT, border=15)

        self.warnMsg = wx.StaticText(self, label=u'非法日期,请重新输入')
        self.warnMsg.SetForegroundColour('red')
        optionSizer.Add(self.warnMsg, pos=(3, 1), span=(1, 3), flag=wx.TOP | wx.LEFT, border=15)
        self.warnMsg.Hide()

        optionOuterSizer.Add(optionSizer)

        fontBtn = wx.Font(13, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.FONTWEIGHT_BOLD)
        btnOuterSizer = wx.StaticBoxSizer(wx.VERTICAL, self, u'操作')
        btnSizer = wx.GridBagSizer(4, 4)
        self.scheduleBtn = wx.Button(self, label=u'开始\n排班', size=(80, 66))
        self.scheduleBtn.SetFont(fontBtn)
        btnSizer.Add(self.scheduleBtn, pos=(0, 0), flag=wx.LEFT | wx.RIGHT, border=12)
        self.scheduleBtn.Enable(False)
        self.Bind(wx.EVT_BUTTON, self.onSchedule, self.scheduleBtn)

        self.exportBtn = wx.Button(self, label=u'导出\n排班', size=(80, 66))
        self.exportBtn.SetFont(fontBtn)
        btnSizer.Add(self.exportBtn, pos=(1, 0), flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=12)
        self.exportBtn.Enable(False)
        self.Bind(wx.EVT_BUTTON, self.onExport, self.exportBtn)

        self.convertDisplayBtn = wx.Button(self, label=u'切换\n排班\n格式', size=(80, 66))
        self.convertDisplayBtn.SetFont(fontBtn)
        btnSizer.Add(self.convertDisplayBtn, pos=(0, 2), span=(0, 1), flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=12)
        self.Bind(wx.EVT_BUTTON, self.onConvertDisplay, self.convertDisplayBtn)

        self.saveBtn = wx.Button(self, label=u'保存\n排班', size=(80, 66))
        self.saveBtn.SetFont(fontBtn)
        btnSizer.Add(self.saveBtn, pos=(0, 1), flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=12)
        self.saveBtn.Enable(False)
        self.Bind(wx.EVT_BUTTON, self.onSaveCalendar, self.saveBtn)

        self.loadBtn = wx.Button(self, label=u'加载\n排班', size=(80, 66))
        self.loadBtn.SetFont(fontBtn)
        btnSizer.Add(self.loadBtn, pos=(1, 1), flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=12)
        self.Bind(wx.EVT_BUTTON, self.onLoadCalendar, self.loadBtn)

        self.deleteBtn = wx.Button(self, label=u'删除\n排班', size=(80, 66))
        self.deleteBtn.SetFont(fontBtn)
        btnSizer.Add(self.deleteBtn, pos=(1, 2), flag=wx.BOTTOM | wx.LEFT | wx.RIGHT, border=12)
        self.Bind(wx.EVT_BUTTON, self.onDeleteCalendar, self.deleteBtn)

        btnOuterSizer.Add(btnSizer)

        outerSizer = wx.BoxSizer(orient=wx.HORIZONTAL)
        outerSizer.Add(optionOuterSizer)
        outerSizer.AddSpacer(15)
        outerSizer.Add(btnOuterSizer)

        self.vBox.Add(outerSizer, wx.ALIGN_TOP | wx.ALIGN_LEFT, 10)