class Read_Cheat_Sheet(QWidget): def __init__(self, font, size_policy, base_directory): super().__init__() self.setWindowIcon(QIcon('BEI_Logo.png')) self.setWindowTitle('Cheat Sheet Reading') self.font = font self.size_policy = size_policy self.base_directory = base_directory self.setup() def setup(self): '''Setup the cheat sheet viewing ''' self.display = QTextEdit(self) self.display.setFont(self.font) self.display.setSizePolicy(self.size_policy, self.size_policy) self.display.setReadOnly(True) self.options = QListView(self) self.options.setFont(self.font) self.options.setSizePolicy(self.size_policy, self.size_policy) # self.options.setReadOnly(True) self.options.setEditTriggers(QAbstractItemView.NoEditTriggers) layout = QHBoxLayout(self) layout.addWidget(self.options) layout.addWidget(self.display) self.setLayout(layout) #get the different topics from cheat_sheet_topics.txt c = open( os.path.join(os.path.join(self.base_directory, 'Cheat_Sheets'), 'Topics.txt'), 'r') c_data = c.readlines() c.close() if len(c_data) == 0: replay = QMessageBox.information( self, 'No Cheat Sheets', 'There are currently no cheat sheets', QMessageBox.Ok) if replay == QMessageBox.Ok: self.close() else: self.topics = [] for i in c_data: self.topics.append(i.replace('\n', '')) self.entry = QStandardItemModel() self.options.setModel(self.entry) self.options.doubleClicked[QModelIndex].connect(self.openFile) for tex in self.topics: self.entry.appendRow(QStandardItem(tex)) self.show() def openFile(self, index): item = self.entry.itemFromIndex(index) text = str(item.text()).replace(' ', '_') #open the text file associated with the clicked item u = open( os.path.join(os.path.join(self.base_directory, 'Cheat_Sheets'), '{}.txt'.format(text)), 'r') data = u.readlines() u.close() combi = '' for i in data: combi += i self.display.setText(combi)
class Viewer(QMainWindow): loaded_spectrum = {} count_rates = {} plotted_spectrum = [] e_plot = [] e_calibration = [] mini = 0 maxi = 14 plotted_tracking = [] not_plotted_tracking = [] def __init__(self): super().__init__() self.size_policy = QSizePolicy.Expanding self.font = QFont() self.font.setPointSize(12) self.setWindowTitle('Calibrated Spectrum Viewer') self.menu() self.geometry() self.showMaximized() self.show() def menu(self): self.menuFile = self.menuBar().addMenu('&File') self.load_new = QAction('&Load New Spectrum') self.load_new.triggered.connect(self.new_spectrum) self.load_new.setShortcut('Ctrl+O') self.load_new.setToolTip('Load a new calibrated spectrum') self.save_figure = QAction('&Save Spectrum Image') self.save_figure.triggered.connect(self.save_fig) self.save_figure.setShortcut('Ctrl+Shift+S') self.save_spec = QAction('&Save Spe File') self.save_spec.triggered.connect(self.spe) self.save_spec.setShortcut('Ctrl+S') self.menuFile.addActions( [self.load_new, self.save_figure, self.save_spec]) self.menuEdit = self.menuBar().addMenu('&Edit') self.calibrate_spectrum = QAction('&Calibrate Spectrum') self.calibrate_spectrum.triggered.connect(self.spectrum_calibrate) self.calibrate_spectrum.setShortcut('Ctrl+G') self.calibrate_spectrum.setToolTip('Calibrate a raw spectrum') self.menuEdit.addActions([self.calibrate_spectrum]) self.change_zoom = QAction('&Change Zoom Location') self.change_zoom.triggered.connect(self.zoom_change) self.change_zoom.setShortcut('Ctrl+Z') self.change_zoom.setToolTip('Change the initial zoom on the spectrum') self.menuView = self.menuBar().addMenu('&View Spectrum Data') self.view_energies = QAction('&View Energies') self.view_energies.setToolTip('Add Vertical Energy Lines') self.view_energies.triggered.connect(self.vert_lines) self.view_calibration_energies = QAction('&Calibration Energies') self.view_calibration_energies.triggered.connect(self.calib_lines) self.view_countrate = QAction('&Count Rates') self.view_countrate.triggered.connect(self.rate_tracking) self.roi_uncertainty = QAction('&ROI Uncertainties') self.roi_uncertainty.triggered.connect(self.roi_count_rate_uncertainty) self.res_action = QAction('&Energy Resolution') self.res_action.triggered.connect(self.find_peaks) self.menuView.addActions([ self.view_energies, self.change_zoom, self.view_calibration_energies, self.view_countrate, self.roi_uncertainty, self.res_action ]) self.menuList = self.menuBar().addMenu('&List Mode Data Analysis') self.timing_window = QAction('&View Time Decay') self.timing_window.triggered.connect(self.time_display) self.list_mode = QAction('&Analyze List Mode Data') self.list_mode.triggered.connect(self.list_moder) self.detection_probability = QAction('&Detection Probability') self.detection_probability.triggered.connect(self.detec_prob) self.dieaway = QAction('&Analyze Die Away') self.dieaway.triggered.connect(self.bck_die_away) self.video = QAction('&Save Probability Videos') self.video.triggered.connect(self.save_detec_videos) self.view_probs = QAction('&View Detection Probability') self.view_probs.triggered.connect(self.view_probabilities) self.menuList.addActions([ self.timing_window, self.list_mode, self.detection_probability, self.dieaway, self.video, self.view_probs ]) def geometry(self): self.open_ = QDockWidget('Loaded Spectrums') #initialize the widget to be used for loading the spectrum self.open_spectrum = QListView(self) self.open_spectrum.setFont(self.font) self.open_spectrum.setSizePolicy(self.size_policy, self.size_policy) self.open_spectrum.setEditTriggers(QAbstractItemView.NoEditTriggers) self.loader = QStandardItemModel() self.open_spectrum.setModel(self.loader) self.open_spectrum.doubleClicked[QModelIndex].connect(self.update_add) self.open_.setWidget(self.open_spectrum) self.addDockWidget(Qt.LeftDockWidgetArea, self.open_) #initialize the widget to remove a spectrum from the plotter self.close_ = QDockWidget('Plotted Spectrum') self.close_spectrum = QListView(self) self.close_spectrum.setFont(self.font) self.close_spectrum.setSizePolicy(self.size_policy, self.size_policy) self.close_spectrum.setEditTriggers(QAbstractItemView.NoEditTriggers) self.unloader = QStandardItemModel() self.close_spectrum.setModel(self.unloader) self.close_spectrum.doubleClicked[QModelIndex].connect( self.update_close) self.close_.setWidget(self.close_spectrum) self.addDockWidget(Qt.RightDockWidgetArea, self.close_) #add the plot window self.plot_window = QWidget() layout = QVBoxLayout() self.figure = Figure() self._canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self._canvas, self) layout.addWidget(self.toolbar) layout.addWidget(self._canvas) self.plot_window.setLayout(layout) self.setCentralWidget(self.plot_window) self.static_ax = self._canvas.figure.subplots() self.static_ax.set_yscale('log') self.static_ax.set_xlim(0, 14) self.static_ax.set_xlabel('Energy [MeV]') self.static_ax.set_ylabel('Count Rate [cps]') self.figure.tight_layout() def new_spectrum(self): self.vals = New() self.vals.add.clicked.connect(self.new_getter) def new_getter(self): self.vals.add_spectrum() counts = self.vals.counts calibr = self.vals.calibration legend = self.vals.legend.text() accum_time = self.vals.accum_time self.count_rates[legend] = self.vals.count_rate self.loaded_spectrum[legend] = [calibr, counts, accum_time] self.loader.appendRow(QStandardItem(legend)) self.not_plotted_tracking.append(legend) def vert_lines(self): self.widget = QWidget() self.widget.setWindowTitle('Add Energies') current_lines = '' for i in range(len(self.e_plot)): if i != 0: current_lines += ',{}'.format(self.e_plot[i]) else: current_lines += '{}'.format(self.e_plot[i]) self.line = QLineEdit(self) self.line.setFont(self.font) self.line.setSizePolicy(self.size_policy, self.size_policy) self.line.setToolTip('Enter energies in MeV, seperated by commas') self.line.setText(current_lines) self.line_label = QLabel('Energies:', self) self.line_label.setFont(self.font) self.line_label.setSizePolicy(self.size_policy, self.size_policy) self.add = QPushButton('Update') self.add.setFont(self.font) self.add.setSizePolicy(self.size_policy, self.size_policy) self.add.clicked.connect(self.add_lines) layout = QGridLayout() layout.addWidget(self.line_label, 0, 0) layout.addWidget(self.line, 0, 1) layout.addWidget(self.add, 1, 0, 1, 2) self.widget.setLayout(layout) self.widget.show() def calib_lines(self): self.widget1 = QWidget() self.widget1.setWindowTitle('Add Energies') current_lines = '' for i in range(len(self.e_calibration)): if i != 0: current_lines += ',{}'.format(self.e_calibration[i]) else: current_lines += '{}'.format(self.e_calibration[i]) self.line1 = QLineEdit(self) self.line1.setFont(self.font) self.line1.setSizePolicy(self.size_policy, self.size_policy) self.line1.setToolTip( 'Enter energies in MeV used for calibration, seperated by commas') self.line1.setText(current_lines) self.line_label1 = QLabel('Energies:', self) self.line_label1.setFont(self.font) self.line_label1.setSizePolicy(self.size_policy, self.size_policy) self.add1 = QPushButton('Update') self.add1.setFont(self.font) self.add1.setSizePolicy(self.size_policy, self.size_policy) self.add1.clicked.connect(self.add_cal_lines) layout = QGridLayout() layout.addWidget(self.line_label1, 0, 0) layout.addWidget(self.line1, 0, 1) layout.addWidget(self.add1, 1, 0, 1, 2) self.widget1.setLayout(layout) self.widget1.show() def add_lines(self): text = self.line.text().split(sep=',') try: self.e_plot = [float(i) for i in text] except: self.e_plot = [] self.widget.close() self.replot() def add_cal_lines(self): text = self.line1.text().split(sep=',') try: self.e_calibration = [float(i) for i in text] except: self.e_calibration = [] self.widget1.close() self.replot() def zoom_change(self): self.change_zoomed = QWidget() min_label = QLabel('Min:[MeV]', self) min_label.setFont(self.font) min_label.setSizePolicy(self.size_policy, self.size_policy) max_label = QLabel('Max:[MeV]', self) max_label.setFont(self.font) max_label.setSizePolicy(self.size_policy, self.size_policy) self.min_ = QLineEdit(self) self.min_.setFont(self.font) self.min_.setSizePolicy(self.size_policy, self.size_policy) self.min_.setText(str(self.mini)) self.max_ = QLineEdit(self) self.max_.setFont(self.font) self.max_.setSizePolicy(self.size_policy, self.size_policy) self.max_.setText(str(self.maxi)) self.add_ = QPushButton('Update') self.add_.setFont(self.font) self.add_.setSizePolicy(self.size_policy, self.size_policy) self.add_.clicked.connect(self.zoomed_update) layout = QGridLayout() layout.addWidget(min_label, 0, 0) layout.addWidget(self.min_, 0, 1) layout.addWidget(max_label, 1, 0) layout.addWidget(self.max_, 1, 1) layout.addWidget(self.add_, 2, 0, 1, 2) self.change_zoomed.setLayout(layout) self.change_zoomed.show() def zoomed_update(self): self.mini = float(self.min_.text()) self.maxi = float(self.max_.text()) self.change_zoomed.close() self.replot() def update_add(self, index): item = self.loader.itemFromIndex(index) val = item.text() self.plotted_spectrum.append(val) #add the item selected to the plotted side self.plotted_tracking.append(val) self.unloader.appendRow(QStandardItem(val)) #remove all the values from the add plot self.loader.removeRows(0, self.loader.rowCount()) #remove the values clicked from the not plotted list self.not_plotted_tracking.remove(val) #add the remaining items back to the options for i in self.not_plotted_tracking: self.loader.appendRow(QStandardItem(i)) self.replot() def update_close(self, index): item = self.unloader.itemFromIndex(index) val = item.text() self.plotted_spectrum.remove(val) #add the value to the not plotted side self.not_plotted_tracking.append(val) self.loader.appendRow(QStandardItem(val)) #remove all the values from the unloading side self.unloader.removeRows(0, self.unloader.rowCount()) #remove the value from the tracking list self.plotted_tracking.remove(val) #put the items back into the unloader for i in self.plotted_tracking: self.unloader.appendRow(QStandardItem(i)) self.replot() def replot(self): self.static_ax.clear() self.mouse_tracking() self.static_ax.set_yscale('log') self.static_ax.set_xlim(self.mini, self.maxi) self.static_ax.set_xlabel('Energy [MeV]') self.static_ax.set_ylabel('Count Rate [cps]') current = list(self.static_ax.get_xticks()) for i in self.e_plot: current.append(i) self.static_ax.axvline(i, color='r', linestyle='--', linewidth=0.8) for i in self.e_calibration: current.append(i) self.static_ax.axvline(i, color='k', linestyle='-', linewidth=1) for i in self.plotted_spectrum: spec = self.loaded_spectrum[i] self.static_ax.plot(spec[0], spec[1], label='{}, Accum Time: {}s'.format(i, spec[2])) current = [round(float(k), 2) for k in current] self.static_ax.set_xticks(current) self.static_ax.set_xticklabels(current, rotation=90) self.static_ax.legend(prop={'size': 18}) # self.static_ax.tick_params(labelsize=18) self._canvas.draw() self.figure.tight_layout() def save_fig(self): options = 'Portable Network Graphics (*.png);;' options_ = 'Joint Photographic Experts Group(*.jpg)' options = options + options_ file_name, ok = QFileDialog.getSaveFileName(self, 'Spectrum Image Save', "", options) if file_name and ok: self.figure.savefig(file_name, dpi=600, figsize=(10, 10)) def spectrum_calibrate(self): '''Launch a calibration window ''' self.calibrator = Window() def rate_tracking(self): '''Show the count rate for all the loaded spectrum ''' self.rater = QWidget() self.rater.setWindowTitle('Count Rates') editor = QTextEdit() editor.setFont(self.font) editor.setReadOnly(True) editor.setSizePolicy(self.size_policy, self.size_policy) for i in list(self.count_rates.keys()): editor.append('{}: {:,.2f}cps'.format(i, self.count_rates[i])) layout = QVBoxLayout() layout.addWidget(editor) self.rater.setLayout(layout) self.rater.show() def mouse_tracking(self): self.txt = self.static_ax.text(0.85, 0.6, "", transform=self.static_ax.transAxes) self.figure.canvas.mpl_connect('motion_notify_event', self.mouse_move) def mouse_move(self, event): if not event.inaxes: return self.txt.set_text('Energy: {:,.3f} MeV'.format(event.xdata)) self._canvas.draw() def roi_display(self): '''Determine the number of counts in a specified ROI and display them ''' self.change_roi = QWidget() min_label = QLabel('Min:[MeV]', self) min_label.setFont(self.font) min_label.setSizePolicy(self.size_policy, self.size_policy) max_label = QLabel('Max:[MeV]', self) max_label.setFont(self.font) max_label.setSizePolicy(self.size_policy, self.size_policy) self.min_roi = QLineEdit(self) self.min_roi.setFont(self.font) self.min_roi.setSizePolicy(self.size_policy, self.size_policy) self.max_roi = QLineEdit(self) self.max_roi.setFont(self.font) self.max_roi.setSizePolicy(self.size_policy, self.size_policy) self.add_roi = QPushButton('Update') self.add_roi.setFont(self.font) self.add_roi.setSizePolicy(self.size_policy, self.size_policy) self.add_roi.clicked.connect(self.roi_update) layout = QGridLayout() layout.addWidget(min_label, 0, 0) layout.addWidget(self.min_roi, 0, 1) layout.addWidget(max_label, 1, 0) layout.addWidget(self.max_roi, 1, 1) layout.addWidget(self.add_roi, 2, 0, 1, 2) self.change_roi.setLayout(layout) self.change_roi.show() def roi_update(self): self.change_roi.close() roi_counts = {} for i in self.plotted_spectrum: calibration = self.loaded_spectrum[i] ma = 0 mi = len(calibration[0]) for j in range(len(calibration[0])): if calibration[0][j] <= float(self.max_roi.text()): ma = j if calibration[0][j] <= float(self.min_roi.text()): # print(calibration[0][j]) mi = j # print(mi,ma) roi_counts[i] = self.loaded_spectrum[i][1][mi:ma] # scale the rois by the accumulation time and determine the sum of the # area using np roi = {} for i in list(roi_counts.keys()): timer = float(self.loaded_spectrum[i][2]) scale = 0 for j in range(len(roi_counts[i])): scale += roi_counts[i][j] #*timer roi[i] = scale self.roi_counts = roi if self.display == False: self.uncertain() if self.display: self.display_roi = QWidget() self.display_roi.setWindowTitle('ROI counts') rois = QTextEdit() rois.setFont(self.font) rois.setSizePolicy(self.size_policy, self.size_policy) for i in list(roi.keys()): rois.append('{}: {:.4f} cps'.format(i, roi[i])) layout = QVBoxLayout() layout.addWidget(rois) self.display_roi.setLayout(layout) self.display_roi.show() self.display = True def spe(self): '''Save the selected file out to an spe file format, even though the calibration will likely not be correct ''' items = self.loaded_spectrum.keys() text, ok = QInputDialog.getItem(self, 'Save Spectrum', 'Saving:', items, 0, False) if ok and text: name = QFileDialog.getSaveFileName(self, 'Spe File Name', '', 'IAEA (*.spe)') if name != " ": try: Save_Spe(self.loaded_spectrum[text], text, name) except: pass def time_display(self): self.di = Time_Window() def list_moder(self): self.lm = List_Mode_Viewer() def roi_count_rate_uncertainty(self): '''Calculate the std of the ROI count rates-- will eventaully have the ability to indicate which loaded spectrum are desired''' self.display = False self.roi_display() # self.display=True def uncertain(self): # now to select the foreground and background spectrum: foreground, ok = QInputDialog.getItem(self, 'Foreground', 'Select Foreground', self.roi_counts.keys(), 0, False) background, ok2 = QInputDialog.getItem(self, 'Background', 'Select Background', self.roi_counts.keys(), 0, False) if ok and ok2: #get the count rates from both of them uncer = net_std(self.roi_counts[foreground], self.roi_counts[background]) u = uncer.calculate_uncertainties() net_cr = self.roi_counts[foreground] - self.roi_counts[background] self.uncertainty_display(u, net_cr, foreground, background) def uncertainty_display(self, net_uncer, net_count_rate, foreground, background): self.rateu = QWidget() self.rateu.setWindowTitle('Count Rates') editor = QTextEdit() editor.setFont(self.font) editor.setReadOnly(True) editor.setSizePolicy(self.size_policy, self.size_policy) fore_cps = self.roi_counts[foreground] back_cps = self.roi_counts[background] editorappd = [ 'Foreground: {}: {:.3f} +\- {:.3f} cps'.format( foreground, fore_cps, fore_cps**0.5), 'Background: {}: {:.3f} +\- {:.3f} cps'.format( background, back_cps, back_cps**0.5), 'Net: {:.3f} +\- {:.3f} cps'.format(net_count_rate, net_uncer) ] for i in editorappd: editor.append(i) layout = QVBoxLayout() layout.addWidget(editor) self.rateu.setLayout(layout) self.rateu.show() def bck_die_away(self): #get the file file_name, ok = QFileDialog.getOpenFileName( self, 'Background Die Away List Mode File', "", 'Comma Seperated File (*.csv);;Text File (*.txt)') num_bins, ok2 = QInputDialog.getInt(self, 'Enter number of bins', 'Bins:', 300, 0, 10000) if file_name != '' and ok and ok2: cts, time = bkg(file_name, num_bins).process_data() io = max(cts[1::]) index = (np.abs(cts - io / 2)).argmin() t_12 = time[index] lambd = np.log(2) / t_12 fit = [io * np.exp(-lambd * i) for i in time] plt.plot(time[1::], cts[1::], '*') # plt.plot(time[1::],fit[1::]) plt.ylabel('Count Rate (cps)') plt.xlabel('Time (s)') plt.show() f = open('Back_Die_Away.csv', 'w') f.write('Time,Counts\n') for i in range(len(cts)): f.write('{:.5f},{:.5f}\n'.format(cts[i], time[i])) f.close() def detec_prob(self): #get the foreground and background file names and info #get the file file_nameb, ok = QFileDialog.getOpenFileName( self, 'Background List Mode File', "", 'Comma Seperated File (*.csv);;Text File (*.txt)') file_namef, ok2 = QFileDialog.getOpenFileName( self, 'Foreground List Mode File', "", 'Comma Seperated File (*.csv);;Text File (*.txt)') if ok and ok2: num, ok3 = QInputDialog.getInt(self, 'Detection Probability', 'Percentage:', 99, 0, 100) if ok3: evals = np.linspace(0, 1800, 181) detection_probability = DT(file_namef, file_nameb, evals) probs = detection_probability.probs probs = [i * 100 for i in probs] #need to parse through the probabilities and find the first #real data point that doesn't represent a statistical anamoly #set a lower threshold to start counting at threshold = 90 #if the probability drops below this s_index = 0 for i in range(len(probs)): if probs[i] <= threshold: s_index = i break probs = probs[s_index::] evals = evals[s_index::] time_detect = np.interp(num, probs, evals) plt.figure(1) plt.plot(evals, probs, '*') plt.axvline( time_detect, label='Time to {}% detection probability: {:.2f}s'.format( num, time_detect)) plt.xlabel('Time(s)') plt.ylabel('Probability (%)') plt.legend() # print(probs) plt.show() #save the raw data out fore_sums = detection_probability.f_sums[s_index::] back_sums = detection_probability.b_sums[s_index::] analysis_times = detection_probability.a_times[s_index::] raw_name, ok3 = QFileDialog.getSaveFileName( self, 'Raw Data Save File Name', "", 'Comma Seperated File (*.csv);;Text File (*.txt)') if ok3: f = open(raw_name, 'w') for i in range(len(fore_sums)): f.write('{},{},{:.4f},{:.4f}\n'.format( fore_sums[i], back_sums[i], analysis_times[i], probs[i])) f.close() def save_detec_videos(self): file_nameb, ok = QFileDialog.getOpenFileName( self, 'Raw Data File', "", 'Comma Seperated File (*.csv);;Text File (*.txt)') file_nameg, ok1 = QFileDialog.getSaveFileName(self, 'Curve Save File', "", 'Multimeda (*.mp4)') file_namep, ok2 = QFileDialog.getSaveFileName(self, 'Probability Save File', "", 'Multimeda (*.mp4)') if ok and ok1 and ok2: Movie = movie(file_nameb, file_nameg, file_namep) Movie.save_gaussian() Movie.save_probability() def find_peaks(self): #first get all the plotted spectrum names loaded_spectrum = self.plotted_spectrum selection, ok = QInputDialog.getItem(self, 'Energy Resolution', 'Selection', loaded_spectrum, 0, False) if ok: x = self.loaded_spectrum[selection][1] y = self.loaded_spectrum[selection][0] #then let the user select which one to pick #then get the counts to analyze peaks, properties = signal.find_peaks(x, width=3, distance=2) e_res = [] widths = properties['widths'] #the fwhm of the peak left = properties['left_ips'] #left point of the fwhm right = properties['right_ips'] #right point of the fwhm sigma = [i / (2 * np.sqrt(2 * np.log(2))) for i in widths] #standard deviation left_sig = [] right_sig = [] #recalculate the peak location based on the average fo the left and right fwhm for i in range(len(peaks)): avg = (left[i] + right[i]) / 2 peaks[i] = avg left_sig.append(avg - 4 * sigma[i]) right_sig.append(avg + 4 * sigma[i]) e_res.append(widths[i] / avg * 100) plt.plot(y, x) plt.yscale('log') _, y_max = plt.gca().get_ylim() y_max = y_max - .5 * y_max for i in range(len(peaks)): plt.axvline(y[int(peaks[i])], linestyle='--', color='m', linewidth=1) v = y[int(peaks[i])] + 0.005 * y[int(peaks[i])] plt.annotate('{:.2f}%'.format(e_res[i]), xy=(v, y_max), rotation='vertical', color='m') # plt.axvspan(y[int(left_sig[2])],y[int(right_sig[2])],facecolor='g',alpha=0.5) plt.show() return peaks, e_res def view_probabilities(self): self.view = Plotter()
class Calibration_Window(QMainWindow): '''Open a calibration window that allows the user to select the calibration style. Allows the user to click on location in graph to select the channels to calibrate and gets the required energy at that point ''' counts = [] channels = [] calibration_lines = [] energies = {} def __init__(self): super().__init__() self.font = QFont() self.font.setPointSize(12) self.size_policy = QSizePolicy.Expanding self.setWindowTitle('Energy Calibration') self.menu() self.geometry() self.mouse_tracking() self.showMaximized() self.show() def menu(self): self.menuFile = self.menuBar().addMenu('&File') self.load_new = QAction('&Load New Spectrum') self.load_new.triggered.connect(self.new_spectrum) self.load_new.setShortcut('Ctrl+O') self.load_new.setToolTip('Load a raw spectrum') self.rebin_action = QAction('&Rebin Data') self.rebin_action.triggered.connect(self.rebin) self.rebin_action.setEnabled(False) self.rebin_action.setShortcut('Ctrl+B') self.rebin_action_save = QAction('&Save Rebin Count') self.rebin_action_save.triggered.connect(self.save_rebinned) self.rebin_action_save.setEnabled(False) self.rebin_action_save.setShortcut('Ctrl+Shift+S') self.calibrateAction = QAction('&Calibrate') self.calibrateAction.triggered.connect(self.calibration) self.calibrateAction.setShortcut('Ctrl+C') self.calibrateAction.setDisabled(True) self.save = QAction('&Save Calibration') self.save.triggered.connect(self.save_) self.save.setShortcut('Ctrl+S') self.save.setDisabled(True) self.menuFile.addActions([ self.load_new, self.rebin_action, self.calibrateAction, self.save, self.rebin_action_save ]) def geometry(self): '''Setup the geometry ''' self.added_values = QListView(self) self.added_values.setFont(self.font) self.added_values.setSizePolicy(self.size_policy, self.size_policy) self.added_values.setEditTriggers(QAbstractItemView.NoEditTriggers) self.added_ = QDockWidget('Calibration Values') self.added_.setWidget(self.added_values) self.addDockWidget(Qt.LeftDockWidgetArea, self.added_) self.loaded = QStandardItemModel() self.added_values.setModel(self.loaded) self.added_values.doubleClicked[QModelIndex].connect(self.update) self.calibrate = QPushButton('Calibrate') self.calibrate.setFont(self.font) self.calibrate.setSizePolicy(self.size_policy, self.size_policy) self.calibrate.clicked.connect(self.calibration) self.plot = QWidget() layout = QVBoxLayout() self.figure = Figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.plot.setLayout(layout) self.ax = self.canvas.figure.subplots() self.ax.set_yscale('log') self.ax.set_xlabel('Channel') self.ax.set_ylabel('Counts') self.figure.tight_layout() self.calibrated_plot = QWidget() layout1 = QVBoxLayout() self.figure1 = Figure() self.canvas1 = FigureCanvas(self.figure1) self.toolbar1 = NavigationToolbar(self.canvas1, self) layout1.addWidget(self.toolbar1) layout1.addWidget(self.canvas1) self.calibrated_plot.setLayout(layout1) self.ax1 = self.canvas1.figure.subplots() self.ax1.set_yscale('log') self.ax1.set_xlabel('Energy (MeV)') self.ax1.set_ylabel('Counts') self.ax1.set_title('Current Linear Calibration') self.figure1.tight_layout() main = QWidget() main_lay = QVBoxLayout() main_lay.addWidget(self.plot) main_lay.addWidget(self.calibrated_plot) main.setLayout(main_lay) self.setCentralWidget(main) def mouse_tracking(self): self.lx = self.ax.axvline(color='k', linestyle='--') self.txt = self.ax.text(0.8, 0.9, "", transform=self.ax.transAxes) self.figure.canvas.mpl_connect('motion_notify_event', self.mouse_move) def mouse_move(self, event): if not event.inaxes: return x = event.xdata self.lx.set_xdata(x) self.txt.set_text('Channel: {:.2f}'.format(x)) self.canvas.draw() def mouse_click(self, event): if not event.inaxes: return if event.dblclick: if event.button == 3: e, ok = QInputDialog.getDouble(self, 'Energy', 'Energy:(MeV)', 10, 0, 15, 10) if ok: self.calibration_lines.append(round(event.xdata, 2)) self.energies['{:.2f}'.format( event.xdata)] = '{:.4f}'.format(e) self.loaded.appendRow( QStandardItem('Ch: {:.2f}->Energy: {:.4f} MeV'.format( event.xdata, e))) if len(self.calibration_lines) >= 2: self.calibrateAction.setEnabled(True) self.replot() def new_spectrum(self): #load the file from a text or csv file fileName, ok = QFileDialog.getOpenFileName( self, 'Raw Spectrum', '', 'Text File (*.txt);;Comma Seperate File (*.csv);;IAEA(*.spe)') if ok and fileName != '': #clear the list view to start calibrating again self.loaded.removeRows(0, self.loaded.rowCount()) self.energies = {} self.calibration_lines = [] self.counts = [] self.channels = [] if '.spe' not in fileName.lower(): f = open(fileName, 'r') f_data = f.readlines() f.close() headers = f_data[0].split(sep=',') h_space = f_data[0].split(sep=' ') mult = False if len(headers) > 1 or len(h_space) > 1: headers[-1] = headers[-1].split(sep='\n')[0] item, ok = QInputDialog.getItem(self, 'Select Data Header', 'Header:', headers, 0, False) if ok: column = headers.index(item) else: mult = True column = 0 if ok or mult: for i in range(len(f_data)): try: self.counts.append( float(f_data[i].split(sep=',')[column])) self.channels.append(i) except: True else: self.counts, self.channels = self.load_spe(fileName) self.rebin_action.setEnabled(True) self.rebin_action_save.setEnabled(True) self.replot(left_lim=0, right_lim=len(self.channels) + 0.01 * len(self.channels)) def find_peaks(self, x, width, distance): peaks, properties = signal.find_peaks(x, width=width, distance=distance) e_res = [] widths = properties['widths'] #the fwhm of the peak left = properties['left_ips'] #left point of the fwhm right = properties['right_ips'] #right point of the fwhm sigma = [i / (2 * np.sqrt(2 * np.log(2))) for i in widths] #standard deviation left_sig = [] right_sig = [] #recalculate the peak location based on the average fo the left and right fwhm for i in range(len(peaks)): avg = (left[i] + right[i]) / 2 peaks[i] = avg left_sig.append(avg - 4 * sigma[i]) right_sig.append(avg + 4 * sigma[i]) e_res.append(widths[i] / avg * 100) return peaks, e_res, left_sig, right_sig def replot(self, left_lim=None, right_lim=None): '''Redraw the uncalibrated spectrum''' l, r = self.ax.get_xlim() self.ax.clear() self.mouse_tracking() self.figure.canvas.mpl_connect('button_press_event', self.mouse_click) self.ax.set_yscale('log') self.ax.set_xlabel('Channel') self.ax.set_ylabel('Counts') self.ax.plot(self.channels, self.counts) if left_lim != None and right_lim != None: self.ax.set_xlim(left_lim, right_lim) else: self.ax.set_xlim(l, r) #let an algorithm find the peaks peaks = self.find_peaks(self.counts, 3, 2)[0] for i in peaks: self.ax.axvline(x=i, color='r', linestyle='--', linewidth=0.5) for i in self.calibration_lines: self.ax.axvline(x=i, color='k', linestyle='--') self.canvas.draw() self.figure.tight_layout() self.replot_calibration() def replot_calibration(self, left_lim=None, right_lim=None): '''Replot the calibrated spectrum: If 0 data points are entered, set intercept to 0 and set maximum energy to be 3MeV If 1 data point is enetered, set intercep to 0 and find slope to be E/C (energy entered divided by bin num) If 2 or more data points are entered, call the linear calibration functions ''' #calibration channel numbers: self.calibration_lines-> list #calibration energies: self.energies-> dictionary with string of cali as key self.ax1.clear() if len(self.calibration_lines) == 0: #take the channels and scale them from 0-3MeV slope = 3 / len(self.channels) calibrated = [i * slope for i in self.channels] elif len(self.calibration_lines) == 1: #get the energy and channel number ch = self.calibration_lines[0] en = float(self.energies[str(ch)]) #the slope if those divided slope = en / ch calibrated = [i * slope for i in self.channels] else: channels = self.calibration_lines energies = self.energies.values() energies = [float(i) for i in energies] calibrated, m, b = cali(self.channels).linear_least_squares_fit( channels, energies, live_plotter=True) x = max(calibrated) - 0.12 * max(calibrated) y = max(self.counts) / 5 self.ax1.annotate( 'Slope: {:.3f} keV/ch\nIntercept: {:.3f}keV'.format( m * 1000, b * 1000), xy=(x, y)) self.ax1.set_xlim(0, max(calibrated)) self.ax1.set_yscale('log') self.ax1.set_xlabel('Energy (MeV)') self.ax1.set_ylabel('Counts') self.ax1.set_title('Current Linear Calibration') self.ax1.plot(calibrated, self.counts) enr = list(self.energies.values()) enr = [float(i) for i in enr] for i in enr: self.ax1.axvline(x=i, color='k', linestyle='--') self.canvas1.draw() self.figure1.tight_layout() def calibration(self): channels = list(self.energies.keys()) energies = list(self.energies.values()) channels = [float(i) for i in channels] energies = [float(j) for j in energies] #get the calibration method desired items = ('Linear', 'Deviation Pairs', 'External Calibration', 'Segemented Linear') item, ok = QInputDialog.getItem(self, 'Calibration Type', 'Calibration:', items, 0, False) if ok and item: if item == items[0]: self.cal_values = cali(self.channels).linear_least_squares_fit( channels, energies) elif item == items[1]: self.cal_values = cali(self.channels).deviation_pairs( channels, energies) elif item == items[2]: text, ok = QInputDialog.getText( self, 'Slope and Intercept', 'Slope [MeV/Ch],Intercept[MeV]:', QLineEdit.Normal, "") if ok and len(text.split(sep=',')) == 2: vals = text.split(sep=',') self.cal_values = cali(self.channels).external_calibration( float(vals[0]), float(vals[1])) elif item == items[3]: self.cal_values = cali( self.channels).segmented_linear_least_squares( channels, energies) plt.figure(1, figsize=(5, 5)) plt.plot(self.channels, self.cal_values) plt.figure(2, figsize=(5, 5)) plt.plot(self.cal_values, self.counts) plt.xlabel('Energy [MeV]') plt.ylabel('Counts') plt.title('Energy Calibrated Spectrum') plt.yscale('log') plt.xlim(0, 14) plt.show() self.save.setEnabled(True) def save_(self): name, ok = QFileDialog.getSaveFileName( self, 'Calibration Data', '', 'Text File (*.txt);; Comma Seperated File (*.csv)') if ok: f = open(name, 'w') for i in self.cal_values: f.write('{:.8f}\n'.format(i)) def save_rebinned(self): name, ok = QFileDialog.getSaveFileName( self, 'Calibration Data', '', 'Text File (*.txt);; Comma Seperated File (*.csv)') if ok: f = open(name, 'w') for i in self.counts: f.write('{:.8f}\n'.format(i)) def update(self, index): item = self.loaded.itemFromIndex(index) val = item.text() ch = val.split(sep='->')[0].split(sep=': ')[1] self.energies.pop(ch) self.calibration_lines.remove(float(ch)) self.loaded.removeRows(0, self.loaded.rowCount()) for i in self.calibration_lines: self.loaded.appendRow( QStandardItem('Ch: {:.2f}->Energy: {} MeV'.format( i, self.energies[str(i)]))) self.replot() def load_spe(self, file_path): '''Load a spectrum file type using the SPE file format''' f = open(file_path, 'r') data = f.readlines() f.close() counts = [] channels = [] # num_counts=int(data[7].split()[1]) #first find the index for $DATA so s_index = 0 e_index = 0 for i in range(len(data)): if '$DATA:' in data[i]: s_index = i + 2 for i in range(s_index, len(data)): if '$' in data[i]: e_index = i - 1 break for i in range(s_index, e_index): counts.append(float(data[i])) channels.append(i - s_index) return counts, channels def rebin(self): '''rebing the data and the replot it''' values = ['2', '4'] selected, ok = QInputDialog.getItem(self, 'Select Rebin', 'Bins to combine', values, 0, False) if ok: s = int(selected) self.counts = Rebins(self.counts, s).rebinner() self.channels = [i for i in range(len(self.counts))] #need to redo the calibration lines for i in range(len(self.calibration_lines)): self.calibration_lines[i] = round( self.calibration_lines[i] / 2, 2) #next take care of the values shown on the right self.loaded.removeRows(0, self.loaded.rowCount()) channels = self.calibration_lines energies = list(self.energies.values()) channels = [float(i) for i in channels] energies = [float(j) for j in energies] self.energies = {} for i in range(len(energies)): self.energies['{:.2f}'.format(channels[i])] = '{:.4f}'.format( energies[i]) for i in self.calibration_lines: self.loaded.appendRow( QStandardItem('Ch: {:.2f}->Energy: {} MeV'.format( i, self.energies[str(i)]))) self.replot(left_lim=0,right_lim=len(self.channels)+\ 0.01*len(self.channels))
class ColorMapsDialog(object): def __init__(self, title, message, items_selected, imageName): self.title = title self.message = message self.items_selected = items_selected #[s for s in items_selected.split(',')] self.imageName = imageName self.cmObj = ColorMaps() self.CM = self.cmObj.colorMaps form = QFormLayout() form.addRow(QLabel(message)) self.listView = QListView() form.addRow(self.listView) font = QFont() font.setBold(True) font.setPointSize(8) self.listView.setFont(font) model = QStandardItemModel(self.listView) size = QSize(60,30) for item in self.CM: # create an item with a caption standardItem = QStandardItem(item) standardItem.setCheckable(True) if item in self.items_selected: standardItem.setCheckState(True) standardItem.setSizeHint(size) model.appendRow(standardItem) self.listView.setModel(model) def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(530, 447) Dialog.setWindowTitle(self.title) self.buttonBox = QDialogButtonBox(Dialog) self.buttonBox.setGeometry(QRect(10, 390, 511, 32)) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.horizontalLayoutWidget = QWidget(Dialog) self.horizontalLayoutWidget.setGeometry(QRect(9, 10, 511, 363)) self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") self.horizontalLayout = QHBoxLayout(self.horizontalLayoutWidget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.horizontalLayout.addWidget(self.listView) self.label = QLabel(self.horizontalLayoutWidget) self.label.setText("") self.label.setPixmap(QPixmap(self.imageName)) self.label.setAlignment(Qt.AlignCenter) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) self.retranslateUi(Dialog) self.buttonBox.accepted.connect(Dialog.accept) self.buttonBox.rejected.connect(Dialog.reject) QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", self.title)) def itemsSelected(self): selected = [] model = self.listView.model() i = 0 while model.item(i): if model.item(i).checkState(): selected.append(model.item(i).text()) i += 1 return selected
class Edit_Customer_Information(QWidget): def __init__(self, font, size_policy, base_directory): super().__init__() self.setWindowIcon(QIcon('BEI_Logo.png')) self.setWindowTitle('Update Customer Information') self.font = font self.size_policy = size_policy self.base_directory = base_directory self.setup() def setup(self): '''Setup the cheat sheet viewing ''' self.display = QTextEdit(self) self.display.setFont(self.font) self.display.setSizePolicy(self.size_policy, self.size_policy) # self.display.setReadOnly(True) self.options = QListView(self) self.options.setFont(self.font) self.options.setSizePolicy(self.size_policy, self.size_policy) self.options.setEditTriggers(QAbstractItemView.NoEditTriggers) self.save = QPushButton('Update', self) self.save.setFont(self.font) self.save.setSizePolicy(self.size_policy, self.size_policy) self.save.clicked.connect(self.save_info) self.save.setEnabled(False) layout = QGridLayout(self) layout.addWidget(self.options, 0, 0) layout.addWidget(self.display, 0, 1) layout.addWidget(self.save, 1, 0) self.setLayout(layout) #get the different topics from cheat_sheet_topics.txt c = open( os.path.join( os.path.join(self.base_directory, 'Customer_Information'), 'Customers.txt'), 'r') c_data = c.readlines() c.close() if len(c_data) == 0: replay = QMessageBox.information( self, 'No Customers', 'There are currently no customers', QMessageBox.Ok) if replay == QMessageBox.Ok: self.close() else: self.topics = [] for i in c_data: self.topics.append(i.replace('\n', '')) self.entry = QStandardItemModel() self.options.setModel(self.entry) self.options.doubleClicked[QModelIndex].connect(self.openFile) for tex in self.topics: self.entry.appendRow(QStandardItem(tex)) self.show() def openFile(self, index): self.save.setEnabled(True) item = self.entry.itemFromIndex(index) text = str(item.text()).replace(' ', '_') self.customer = text #open the text file associated with the clicked item cust = os.path.join(self.base_directory, 'Customer_Information') u = open( os.path.join(os.path.join(cust, 'Addresses'), '{}.txt'.format(text)), 'r') data = u.readlines() u.close() combi = '' for i in data: combi += i self.display.setText(combi) def save_info(self): cust = os.path.join(self.base_directory, 'Customer_Information') u = open( os.path.join(os.path.join(cust, 'Addresses'), '{}.txt'.format(self.customer)), 'w') u.write(self.display.toPlainText()) u.close() QMessageBox.information(self, 'Saved', '{} information updated'.format(self.customer), QMessageBox.Ok)
class Invoice(QMainWindow): '''Runs the main window of the invoice development Calls the table to be used for parts and labor from table_widget.py ''' invoice_count = 0 total_parts_ = 0 labor_supplies_ = 0 recent_open = False start_flag = False current_job = str labor_ = 0 parts_ = 0 supplies = 0 freight_ = 0 subtotal = 0 taxed = 0 totals = 0 tax = 0 partial = 0 finance = 0 new_total = 0 open_list = [] printed_list = {} def __init__(self): '''Initialize the window and get pertinent information read in: Set the window size Set the picture to be a BEI logo Read in the standard labor rates ''' super().__init__() self.size_policy = QSizePolicy.Expanding self.font = QFont() self.font.setPointSize(12) self.showMaximized() self.setWindowIcon(QIcon('BEI_Logo.png')) # backimage=QImage('BEI_Logo.png') self.setWindowTitle('Burl Equipment Inc. Invoices Beta') self.tray = QSystemTrayIcon(self) self.tray.setIcon(QIcon('BEI_Logo.png')) self.show() self.menu_bar() self.statusbar = QStatusBar() self.setStatusBar(self.statusbar) #this is the first time start up section, should only run the very #first time self.base_directory = str( Path(os.path.join(os.environ['USERPROFILE'], 'BEI_Invoices'))) base_entries = os.listdir(os.environ['USERPROFILE']) if 'BEI_Invoices' not in base_entries: initi.First_Run(self.base_directory) def menu_bar(self): '''Create the menu bar for the main window will include Name: Shortcut: Function called: File: New CTRL+N new_invoice_begin Open CTRL+O existing_invoice_open Save CTRL+S print_invoice Quit ALT save_invoice Print CTRL+P +F4 exit_system Edit: Change Labor Rates labor_rates View: View Totals view_totals View Labor Breakdown labor_breakdown Help: View Current Cheat Sheet cheat_sheet Add New Task to Cheat Sheet add_cheat_task ''' self.menuFile = self.menuBar().addMenu("&File") self.actionNew = QAction('&New', self) self.actionNew.setShortcut('Ctrl+N') self.actionNew.triggered.connect(self.new_invoice_begin) self.actionOpen = QAction("&Open", self) self.actionOpen.setShortcut('Ctrl+O') self.actionOpen.triggered.connect(self.existing_invoice_open) self.actionSave = QAction('&Save', self) self.actionSave.setShortcut('Ctrl+S') self.actionSave.setDisabled(True) self.actionSave.triggered.connect(self.save_invoice) # self.actionImport=QAction('&Import Old Job',self) # self.actionImport.triggered.connect(self.old_job) # self.actionImport.setShortcut('Ctrl+I') self.actionPrint = QAction('&Print', self) self.actionPrint.setShortcut('Ctrl+P') self.actionPrint.setDisabled(True) self.actionPrint.triggered.connect(self.print_invoice) self.printMenu = QMenu('Print Envelopes', self) self.actionEnvelope = QAction('&Print All Billed Customer Envelopes', self) self.actionEnvelope.triggered.connect(self.envelop_write) self.actionEnvelope.setShortcut('Ctrl+E') self.actionEnvelope.setDisabled(True) self.actionEnvelope1 = QAction( '&Print Single Billed Customer Envelope', self) self.actionEnvelope1.triggered.connect(self.envelop_write1) self.actionEnvelope1.setShortcut('Ctrl+R') self.actionBilledEnvelopes = QAction('&Print Check Envelope', self) self.actionBilledEnvelopes.triggered.connect(self.billing_envelopes) self.actionBilledEnvelopes.setShortcut('Ctrl+C') self.printMenu.addActions([ self.actionEnvelope, self.actionEnvelope1, self.actionBilledEnvelopes ]) self.actionQuit = QAction('&Exit', self) self.actionQuit.triggered.connect(self.closing) self.actionQuit.setShortcut('Alt+F4') self.menuFile.addActions([ self.actionNew, self.actionOpen, self.actionSave, self.actionPrint ]) self.menuFile.addMenu(self.printMenu) self.menuFile.addAction(self.actionQuit) self.menuEdit = self.menuBar().addMenu('&Edit') self.menuEdit_Change_In = QMenu('Change Basic Invoice Information', self) self.menuEdit_Change_Sy = QMenu('Change Operating Data', self) self.actionLaborRates = QAction('&Change Standard Labor Rates', self) self.actionLaborRates.triggered.connect(self.labor_rates) self.actionAddTechnician = QAction('&Add Technician', self) self.actionAddTechnician.triggered.connect(self.add_tech) self.actionChangeDate = QAction('&Change Invoice Date', self) self.actionChangeDate.triggered.connect(self.date_change) self.actionChangeCustomerAddress = QAction('&Change Customer Address', self) self.actionChangeCustomerAddress.triggered.connect(self.change_address) self.actionBasicInfo = QAction('&Change Basic Information', self) self.actionBasicInfo.triggered.connect(self.change_basic_info) self.actionBasicInfo.setDisabled(True) self.menuEdit_Change_In.addActions([self.actionBasicInfo]) self.menuEdit_Change_Sy.addActions([ self.actionLaborRates, self.actionAddTechnician, self.actionChangeDate, self.actionChangeCustomerAddress ]) self.menuEdit.addMenu(self.menuEdit_Change_In) self.menuEdit.addMenu(self.menuEdit_Change_Sy) self.menuView = self.menuBar().addMenu('&View') self.actionViewLaborBreakdown = QAction('&View Labor Breakdown', self) self.actionViewLaborBreakdown.setDisabled(True) self.actionViewLaborBreakdown.triggered.connect(self.breakdown) self.actionViewAllWindows = QAction('&View All Windows', self) self.actionViewAllWindows.setDisabled(True) self.actionViewAllWindows.triggered.connect(self.view_windows) self.actionViewCutomer = QAction('&View Customer Invoice', self) self.actionViewCutomer.triggered.connect(self.view_customer) self.actionViewCutomer = QAction('&View Customer Invoice', self) self.actionViewCutomer.triggered.connect(self.view_customer) self.actionViewCutomer.setEnabled(False) self.actionViewCompany = QAction('&View Company Invoice', self) self.actionViewCompany.triggered.connect(self.view_company) self.actionViewCompany.setEnabled(False) self.menuView.addActions([ self.actionViewLaborBreakdown, self.actionViewAllWindows, self.actionViewCutomer, self.actionViewCompany ]) self.actionJobNumbers = QAction('&More Job Numbers', self) self.actionJobNumbers.triggered.connect(self.new_job_nums) self.menuJobNumbers = self.menuBar().addMenu('Job Numbers') self.menuJobNumbers.addAction(self.actionJobNumbers) self.menuPayment = self.menuBar().addMenu('&Finance/Payments') self.actionPartialPayment = QAction('&Partial Payment', self) self.actionPartialPayment.triggered.connect(self.partial_payment) self.actionPartialPayment.setDisabled(True) self.actionFinanceCharges = QAction('&Add Finance Charges', self) self.actionFinanceCharges.triggered.connect(self.finance_charges) self.actionFinanceCharges.setDisabled(True) self.menuPayment.addActions( [self.actionPartialPayment, self.actionFinanceCharges]) self.menuHelp = self.menuBar().addMenu('&Help') self.actionViewCheatSheet = QAction('&View Cheat Sheet', self) self.actionViewCheatSheet.triggered.connect(self.cheat_sheet) self.actionNewCheat = QAction('&Add New Item to Cheat Sheet', self) self.actionNewCheat.triggered.connect(self.add_cheat_task) self.actionUpdate = QAction('&Update Application') self.actionUpdate.triggered.connect(self.updater) self.menuHelp.addActions([ self.actionViewCheatSheet, self.actionNewCheat, self.actionUpdate ]) def new_invoice_begin(self): '''Entering basic information: Job Number: Machine: Customer Name: ''' try: self.docked.close() self.docked2.close() self.totals_table.close() self.save_invoice() self.new_window = New_Invoice(12, self.base_directory) # self.new_window.basic_information() self.new_window.start.clicked.connect(self.job_num_insertion) self.new_window.customer_address_line_2.returnPressed.connect( self.new_window.information_) self.new_window.customer_address_line_2.returnPressed.connect( self.job_num_insertion) except: self.new_window = New_Invoice(12, self.base_directory) # self.new_window.basic_information() self.new_window.start.clicked.connect(self.job_num_insertion) self.new_window.customer_address_line_2.returnPressed.connect( self.new_window.information_) self.new_window.customer_address_line_2.returnPressed.connect( self.job_num_insertion) def job_num_insertion(self): '''Call the table with the job number given in the new invoice ''' self.reset_data() if not self.recent_open: self.recent_invoices() self.tax = self.new_window.tax self.customer = self.new_window.customer.replace('#', '') self.machine_text = self.new_window.machine_ self.current_job = self.new_window.job_num if self.current_job not in self.open_list: self.open_list.append(self.current_job) self.recently_opened_invoice.appendRow( QStandardItem(str(self.current_job))) self.invoice_count += 1 #make the folder for this invoice to be saved in self.job_dire = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), self.current_job) try: os.mkdir(self.job_dire) #save the basic information location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), self.current_job) self.table(self.new_window.job_num) basic = os.path.join(location, 'Basic_Info.csv') f = open(basic, 'w') f.write(str(self.current_job) + '\n') f.write(self.new_window.customer + '\n') f.write(self.new_window.machine_ + '\n') f.write('{},{}\n'.format(str(self.new_window.tax), self.new_window.tax_code)) f.write(self.new_window.line1 + '\n') f.write(self.new_window.line2 + '\n') f.close() except: buttonReply = QMessageBox.question( self, 'Confirm New Machine', 'Job Number {} already exist.\nDo you want to overwrite it?'. format(self.new_window.job_num), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.table(self.new_window.job_num) location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), self.current_job) basic = os.path.join(location, 'Basic_Info.csv') f = open(basic, 'w') f.write(str(self.current_job) + '\n') f.write(self.new_window.customer + '\n') f.write(self.new_window.machine_ + '\n') f.write('{},{}\n'.format(str(self.new_window.tax), self.new_window.tax_code)) f.write(self.new_window.line1 + '\n') f.write(self.new_window.line2 + '\n') f.close() elif buttonReply == QMessageBox.No: self.current_job = str(self.current_job) self.read_in_data() def existing_invoice_open(self): '''Open an existing invoice ''' try: self.docked.close() self.docked2.close() self.save_invoice() except: True if not self.recent_open: self.recent_invoices() #get the saved invoices loc = os.path.join(self.base_directory, 'Saved_Invoices') saved_jobs = os.listdir(loc) self.existing = QWidget() self.existing.setWindowIcon(QIcon('BEI_Logo.png')) self.existing.setWindowTitle('Open Existing Invoice') self.open = QPushButton('Open', self) self.open.setFont(self.font) self.open.setSizePolicy(self.size_policy, self.size_policy) self.open.clicked.connect(self.reader) self.job_to_open = QLineEdit(self) self.job_to_open.setFont(self.font) self.job_to_open.setSizePolicy(self.size_policy, self.size_policy) self.job_to_open.setCompleter(QCompleter(saved_jobs)) # self.job_to_open.returnPressed.connect(self.reader) layout = QVBoxLayout() layout.addWidget(self.job_to_open) layout.addWidget(self.open) self.existing.setLayout(layout) self.existing.setGeometry(400, 400, 300, 100) self.existing.show() def reader(self): self.current_job = self.job_to_open.text() self.read_in_data() self.existing.close() def table(self, num): '''Setup the table for use with a new invoice ''' self.start_flag = True self.actionPrint.setEnabled(True) self.actionSave.setEnabled(True) self.actionViewLaborBreakdown.setEnabled(True) self.actionBasicInfo.setEnabled(True) self.actionViewAllWindows.setEnabled(True) self.actionViewCutomer.setEnabled(True) self.actionViewCompany.setEnabled(True) self.docked = QMdiSubWindow() self.docked.setWindowTitle('Invoice {}'.format(num)) self.num = num self.tabs = QTabWidget(self) self.parts = Parts_Tabs(num) self.tabs.addTab(self.parts, 'Parts') self.labor = Labor_Tabs(num) self.tabs.addTab(self.labor, 'Labor') self.docked.setWidget(self.tabs) self.parts.total.connect(self.calculate_totals) self.labor.labor_total.connect(self.calculate_totals) cust_display = QWidget(self) self.cust_label = QLabel('Customer: {}'.format(self.customer), self) self.cust_label.setFont(self.font) self.machine_label = QLabel('Machine: {}'.format(self.machine_text), self) self.machine_label.setFont(self.font) lay = QHBoxLayout() lay.addWidget(self.cust_label) lay.addWidget(self.machine_label) cust_display.setLayout(lay) #design and insert the totals table self.totals_table = Table(7, 2) self.totals_table.tableWidget.setItem(0, 0, QTableWidgetItem('Parts:')) self.totals_table.tableWidget.setItem(1, 0, QTableWidgetItem('Labor:')) self.totals_table.tableWidget.setItem(2, 0, QTableWidgetItem('Supplies:')) self.totals_table.tableWidget.setItem(3, 0, QTableWidgetItem('Freight:')) self.totals_table.tableWidget.setItem(4, 0, QTableWidgetItem('Subtotal:')) self.totals_table.tableWidget.setItem( 5, 0, QTableWidgetItem('Tax: {:.2f}%'.format(self.tax * 100))) self.totals_table.tableWidget.setItem(6, 0, QTableWidgetItem('Total:')) #set up the comments section self.comments = QTextEdit(self) self.comments.setFont(self.font) self.comments.setSizePolicy(self.size_policy, self.size_policy) self.comments.setText('Comments:\n') self.additional_docking = QWidget(self) layout = QVBoxLayout(self) layout.addWidget(cust_display) layout.addWidget(self.totals_table) layout.addWidget(self.comments) self.additional_docking.setLayout(layout) self.docked2 = QMdiSubWindow() self.docked2.setWidget(self.additional_docking) self.docked2.setWindowTitle('Information') self.mdi = QMdiArea() self.mdi.addSubWindow(self.docked2) self.mdi.addSubWindow(self.docked) self.mdi.tileSubWindows() self.setCentralWidget(self.mdi) # self.window_saved=self.saveState(1) def recent_invoices(self): '''Show a list of recently opened invoices ''' self.recent_open = True self.recent = QDockWidget('Recently opened invoices', self) self.recently_opened_invoice = QStandardItemModel() self.invoices_open = QListView(self) self.invoices_open.setFont(self.font) self.invoices_open.setSizePolicy(self.size_policy, self.size_policy) self.invoices_open.setModel(self.recently_opened_invoice) self.invoices_open.setEditTriggers(QAbstractItemView.NoEditTriggers) self.invoices_open.doubleClicked[QModelIndex].connect(self.recall) self.notes = QTextEdit(self) self.notes.setFont(self.font) self.notes.setSizePolicy(self.size_policy, self.size_policy) self.notes.setText('Notes:\n') self.running_info = QWidget(self) layout = QVBoxLayout(self) layout.addWidget(self.invoices_open) layout.addWidget(self.notes) self.running_info.setLayout(layout) self.recent.setWidget(self.running_info) self.addDockWidget(Qt.LeftDockWidgetArea, self.recent) def recall(self, index): item = self.recently_opened_invoice.itemFromIndex(index) job_number = item.text() self.docked.close() self.docked2.close() self.save_invoice() self.current_job = job_number self.read_in_data() def save_invoice(self, printing=False): '''Save both the parts and labor tables ''' if self.current_job == str: pass else: location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), self.current_job) parts_file = os.path.join(location, 'Parts.csv') #first read and write the parts information f = open(parts_file, 'w') row = [] for i in range(100): try: for j in range(8): if j == 0: if self.parts.parts_table.tableWidget.item( i, j).text() != '*': val = float( self.parts.parts_table.tableWidget.item( i, j).text()) elif self.parts.parts_table.tableWidget.item( i, j).text() == '*': val = self.parts.parts_table.tableWidget.item( i, j).text() row.append(val) else: try: val = self.parts.parts_table.tableWidget.item( i, j).text() row.append(val) except: row.append('') if '\n' in row[-1]: row[-1] = row[-1].split(sep='\n')[0] row[2] = row[2].replace(',', '.') f.write('{},{},{},{},{},{},{},{}\n'.format(*row)) row = [] except: break f.close() #save the total table total_location = os.path.join(location, 'Totals.csv') h = open(total_location, 'w') t_row = [ self.parts_, self.labor_, self.supplies, self.freight_, self.subtotal, self.taxed, self.totals ] for i in t_row: try: float(i) h.write('{:.2f}\n'.format(i)) except: h.write('0') h.close() #save the comments comments_location = os.path.join(location, 'Comments.csv') v = open(comments_location, 'w') v.write(self.comments.toPlainText()) v.close() #finally save the labor information #get the number of techs showing count = self.labor.counts for l in range(count): labor_location = os.path.join(location, 'tech{}.csv'.format(l)) o = open(labor_location, 'w') #get the data from the labor class tech_labor = self.labor.read_data_out(l) for k in range(len(tech_labor)): if '\n' in list(tech_labor[k][-1]): tech_labor[k][-1] = float(tech_labor[k][-1]) o.write('{},{},{},{},{},{},{},{}\n'.format(*tech_labor[k])) o.close() self.statusbar.showMessage('Invoice {} saved'.format(self.current_job), 5000) envelop_writer = EWriter(self.base_directory, self.current_job) envelop_writer.generate_latex() acrobat = 'Acrobat.exe' in (p.name() for p in psutil.process_iter()) reader = 'AcroRd32.exe' in (p.name() for p in psutil.process_iter()) if acrobat: lis = ['taskkill', '/F', '/IM', 'Acrobat.exe', '/T'] subprocess.call(lis) if reader: os.system('taskkill /F /IM "AcroRd32.exe" /T') if printing == False: comp_cust = Saver(self, self.base_directory, self.current_job) comp_cust.out.connect(self.failure) comp_cust.start() def failure(self, value): if value == 1: QMessageBox.information(self, 'Save Failure', 'Closing PDF and trying again', QMessageBox.Ok) # self.save_invoice() def add_tech(self): '''Adding a technician to the company: Changes to make: Add to the tabs Add standard labor rates Change stuff in the base invoice, not sure how this is going to work yet ''' text, okPressed = QInputDialog.getText(self, "Tech Name", "Tech name:", QLineEdit.Normal, "") if okPressed and text != '': regular, okPressed1 = QInputDialog.getDouble( self, "Regular Rate", "Regular Hourly Rate: $", 80, 0, 150, 2) if okPressed1: overtime, okPressed2 = QInputDialog.getDouble( self, "Overtime Rate", "Overtime Hourly Rate: $", 80, 0, 150, 2) if okPressed2: directory = str( Path( os.path.join( os.path.join(os.environ['USERPROFILE'], 'BEI_Invoices')), 'Basic_Information_Totals')) tech_data = open( str(Path(os.path.join(directory, 'Labor_Rates.csv'))), 'a') tech_data.write('{},{},{}\n'.format( text, regular, overtime)) tech_data.close() QMessageBox.information( self, 'Updated', 'Application must be restarted to apply these changes', QMessageBox.Ok) def read_in_data(self): self.actionPartialPayment.setEnabled(True) self.actionFinanceCharges.setEnabled(True) self.invoice_count += 1 if self.current_job not in self.open_list: self.open_list.append(self.current_job) self.recently_opened_invoice.appendRow( QStandardItem(self.current_job)) #open the basic information and read the tax percentage location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) e = open(os.path.join(location, 'Basic_Info.csv'), 'r') basic = e.readlines() e.close() self.customer, self.machine_text = basic[1].replace( '\n', ''), basic[2].replace('\n', '') self.tax = float(basic[3].split(sep=',')[0]) self.table(self.current_job) self.machine_label.setText('Machine: {}'.format(self.machine_text)) self.cust_label.setText('Customer: {}'.format(self.customer)) #read in the parts data from the file and hand it off the the parts_tab #class to be placed in the table location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) parts_location = os.path.join(location, 'Parts.csv') p_d = open(parts_location, 'r') p_data = p_d.readlines() p_d.close() parts_data = [p_data[i].split(sep=',') for i in range(len(p_data))] self.parts.read_in_data(parts_data) #read in the totals information totals_information = os.path.join(location, 'Totals.csv') t_d = open(totals_information, 'r') t_data = t_d.readlines() t_d.close() totals = [float(i) for i in t_data] #reset all the s self.reset_data() #try to read in payments and finance cahrges if they exist try: par_d = open(os.path.join(location, 'Payments.csv'), 'r') self.partial = float(par_d.readlines()[0]) par_d.close() except: self.partial = 0 try: fin_d = open(os.path.join(location, 'Finance.csv'), 'r') self.finance = float(fin_d.readlines()[0]) fin_d.close() except: self.finance = 0 self.parts_, self.labor_, self.supplies, self.freight_, self.subtotal, self.taxed, self.totals = totals #set the values into the totals table # self.totals=self.totals+self.finance-self.partial for i in range(len(totals)): self.totals_table.tableWidget.setItem( i, 1, QTableWidgetItem('${:,.2f}'.format(totals[i]))) #read and put the comments in place comments_location = os.path.join(location, 'Comments.csv') c_data = open(comments_location, 'r') com_data = c_data.readlines() c_data.close() combi = '' for i in com_data: combi += str(i) self.comments.setText(combi) #read in the labor data #determine the number of tech there are tech_num = 0 dir_ = os.listdir(location) for i in range(len(dir_)): if 'tech' in dir_[i]: tech_num += 1 for l in range(tech_num): loca = os.path.join(location, 'tech{}.csv'.format(l)) l_data = open(loca, 'r') lab_data = l_data.readlines() l_data.close() labor_data = [o.split(sep=',') for o in lab_data] self.labor.read_in_data(l, labor_data) def reset_data(self): self.parts_, self.labor_, self.supplies, self.freight_, self.subtotal, self.taxed, self.totals = [ 0, 0, 0, 0, 0, 0, 0 ] self.partial, self.finance = 0, 0 def labor_rates(self): '''Change the labor rates ''' self.changes = Labor_Rates(self.base_directory, self.font, self.size_policy) self.changes.show() def update_parts_total(self): self.parts_calculator() # self.parts_=round(self.parts.parts_total,2) # self.freight_=round(self.parts.freight_total,2) self.totals_table.tableWidget.setItem( 0, 1, QTableWidgetItem('${:,.2f}'.format(self.parts_))) self.totals_table.tableWidget.setItem( 3, 1, QTableWidgetItem('${:,.2f}'.format(self.freight_))) self.total_parts_ = self.parts_ + self.freight_ def parts_calculator(self): self.parts_ = 0 self.freight_ = 0 # self.parts.parts_sumation() # self.parts_=self.parts.parts_total # self.freight_=self.parts.freight_total+1 for i in range(100): try: self.parts_ += float( self.parts.parts_table.tableWidget.item(i, 5).text()) try: self.freight_ += float( self.parts.parts_table.tableWidget.item(i, 6).text()) except: self.freight_ += 0 except: True def update_labor(self): total_labor = 0 for i in range(self.labor.counts): total_labor += self.labor.find_tech_total(i) self.totals_table.tableWidget.setItem( 1, 1, QTableWidgetItem('${:,.2f}'.format(round(total_labor, 2)))) self.totals_table.tableWidget.setItem( 2, 1, QTableWidgetItem('${:,.2f}'.format(round(total_labor * 0.05, 2)))) self.supplies = round(total_labor * 0.05, 2) self.labor_ = total_labor self.labor_supplies_ = round(self.labor_, 2) + self.supplies def calculate_totals(self): '''Calculate the totals for the totals table and display it ''' self.update_labor() # self.parts.parts_sumation() self.update_parts_total() self.subtotal = self.labor_supplies_ + self.total_parts_ self.totals_table.tableWidget.setItem( 4, 1, QTableWidgetItem('${:,.2f}'.format(self.subtotal))) self.taxed = self.tax * self.subtotal self.totals_table.tableWidget.setItem( 5, 1, QTableWidgetItem('${:,.2f}'.format(self.taxed))) self.totals = self.subtotal + self.taxed + self.finance - self.partial self.totals_table.tableWidget.setItem( 6, 1, QTableWidgetItem('${:,.2f}'.format(self.totals))) def print_invoice(self): ''' Print the customer and company invoices ''' #make sure the invoice is saved self.save_invoice(printing=True) self.printed_list[self.current_job] = [ self.customer, self.machine_text ] try: pdf2.PDF_Builder(self.current_job, self.base_directory, 'Company').print_tex() pdf2.PDF_Builder(self.current_job, self.base_directory, 'Customer').print_tex() except: QMessageBox.information(self, 'Print Failure', 'Close file and try again', QMessageBox.Ok) #first check and see if the Envelopes directory has this #months print list envelope_date = EP(self.base_directory, self.customer, self.current_job) self.envelope_date = envelope_date.dater() self.actionEnvelope.setEnabled(True) self.actionEnvelope1.setEnabled(True) def closing(self): # self.save_invoice() self.close() def breakdown(self): '''view the labor break down ''' #open the labor rates to get the names loc = os.path.join(self.base_directory, 'Basic_Information_Totals') file_loc = os.path.join(loc, 'Labor_Rates.csv') f = open(file_loc, 'r') f_data = f.readlines() f.close() names = [] for i in range(len(f_data)): names.append(f_data[i].split(sep=',')[0]) #get the totals from the labor page individauls = self.labor.find_tech_individual() #combine the two lists into a single string combined = '' for i in range(len(individauls)): combined += '{}: ${:,.2f}\n'.format(names[i], individauls[i]) QMessageBox.information(self, 'Labor Breakdown', combined, QMessageBox.Ok) def date_change(self): '''change the data on the invoices for the month ''' self.date_changed = QWidget() self.date_changed.setWindowTitle('Change Invoice Date') self.date_changed.setWindowIcon(QIcon('BEI_Logo.png')) self.line = QLineEdit() self.line.setFont(self.font) self.line.setSizePolicy(self.size_policy, self.size_policy) self.save_date = QPushButton('Save Date') self.save_date.setFont(self.font) self.save_date.setSizePolicy(self.size_policy, self.size_policy) self.save_date.clicked.connect(self.saved_date) layout = QVBoxLayout() layout.addWidget(self.line) layout.addWidget(self.save_date) self.date_changed.setLayout(layout) d_location = os.path.join(self.base_directory, 'Basic_Information_Totals') self.date_location = os.path.join(d_location, 'Invoice_Date.txt') y = open(self.date_location, 'r') date = y.readlines() y.close() self.line.setText(date[0]) self.date_changed.show() def saved_date(self): ''' Save the new date ''' y = open(self.date_location, 'w') y.write(self.line.text()) y.close() self.date_changed.close() def new_job_nums(self): '''Run the class to create more job numbers ''' self.n_jobs = Job_Numbers() def cheat_sheet(self): '''Open the cheat sheet for viewing ''' self.chea = Read_Cheat_Sheet(self.font, self.size_policy, self.base_directory) def add_cheat_task(self): self.cheat = Write_Cheat_Sheet(self.font, self.size_policy, self.base_directory) def partial_payment(self): self.a = Partial_Payments(self.font, self.size_policy) self.a.add.clicked.connect(self.proce) def proce(self): try: self.a.process() self.this_payment = self.a.amount try: location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) payments = os.path.join(location, 'Payments.csv') f = open(payments, 'r') value = float(f.readlines()[0]) f.close() self.this_payment += value except: self.this_payment = self.this_payment self.comments.append( '''Partial payment of ${:,.2f} on {}, leaves a remaining balance of ${:,.2f}''' .format(self.a.amount, self.a.date, self.totals - self.a.amount)) f = open(payments, 'w') f.write(str(self.this_payment)) self.partial = self.this_payment self.calculate_totals() f.close() except: pass def finance_charges(self): self.charg = Finance_Charges(self.font, self.size_policy) self.charg.add.clicked.connect(self.fin_process) def fin_process(self): self.charg.process() self.finance += self.charg.amount self.comments.append( 'Finance Charge of ${:,.2f} applied on {}, kindly remit payment immediately.' .format(self.charg.amount, self.charg.date)) location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) fin_loc = os.path.join(location, 'Finance.csv') f = open(fin_loc, 'w') f.write(str(self.finance)) f.close() self.calculate_totals() def change_basic_info(self): #first read in the current status of the basic info location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) e = open(os.path.join(location, 'Basic_Info.csv'), 'r') basic = e.readlines() e.close() self.update_info = QWidget() self.update_info.setWindowTitle('Update Basic Information') self.update_info.setWindowIcon(QIcon('BEI_Logo.png')) mach = QLabel('Machine', self) mach.setFont(self.font) mach.setSizePolicy(self.size_policy, self.size_policy) tax = QLabel('Tax [%]', self) tax.setFont(self.font) tax.setSizePolicy(self.size_policy, self.size_policy) self.machine = QLineEdit(self) self.machine.setFont(self.font) self.machine.setSizePolicy(self.size_policy, self.size_policy) self.machine.setText(basic[2]) self.tax_value = QLineEdit(self) self.tax_value.setFont(self.font) self.tax_value.setSizePolicy(self.size_policy, self.size_policy) self.tax_value.setText( str(round(float(basic[3].split(sep=',')[0]) * 100, 2))) update = QPushButton('Update', self) update.setFont(self.font) update.setSizePolicy(self.size_policy, self.size_policy) update.clicked.connect(self.update_basic_values) layout = QGridLayout() layout.addWidget(mach, 0, 0) layout.addWidget(self.machine, 0, 1) layout.addWidget(tax, 1, 0) layout.addWidget(self.tax_value, 1, 1) layout.addWidget(update, 2, 0) self.update_info.setLayout(layout) self.update_info.show() def update_basic_values(self): self.update_info.close() location = os.path.join( os.path.join(self.base_directory, 'Saved_Invoices'), '{}'.format(self.current_job)) e = open(os.path.join(location, 'Basic_Info.csv'), 'r') basic = e.readlines() e.close() flag = False #change the information in basic[2] and basic[3] to match the new values if basic[2].split(sep='\n')[0] != self.machine.text(): old = basic[2].split(sep='\n')[0].replace(' ', '_') cust = basic[1].split(sep='\n')[0].replace(' ', '_') file_name = basic[0].split(sep='\n')[0] + '.pdf' flag = True basic[2] = self.machine.text() self.machine_text = basic[2] self.machine_label.setText('Machine: {}'.format(self.machine_text)) if float(basic[3].split( sep=',')[0]) != float(self.tax_value.text()) / 100: try: tax_code, ok = QInputDialog.getText( self, 'Update Tax Code', 'Tax Code: ', QLineEdit.Normal, basic[3].split(sep=',')[1].split(sep='\n')[0]) except: tax_code, ok = QInputDialog.getText(self, 'Update Tax Code', 'Tax Code: ', QLineEdit.Normal, "") basic[3] = '{},{}'.format( float(self.tax_value.text()) / 100, tax_code) self.tax = float(self.tax_value.text()) / 100 f = open(os.path.join(location, 'Basic_Info.csv'), 'w') for i in range(len(basic)): if '\n' not in basic[i]: f.write('{}\n'.format(basic[i])) else: f.write('{}'.format(basic[i])) f.close() #change the percent shown in the total value self.totals_table.tableWidget.setItem( 5, 0, QTableWidgetItem('Tax: {:.2f}%'.format(self.tax * 100))) #next update the totals self.calculate_totals() self.save_invoice() time.sleep(3) if flag: #depending on if the machine has been updated, get rid of the previous #version of the file and start change it to the new location location = os.path.join(os.path.expanduser('~/Desktop'), 'BEI_Invoices') old_location_cust_ = os.path.join( os.path.join(location, 'Customer'), cust) old_location_cust = os.path.join(old_location_cust_, old) old_final_cust = os.path.join(old_location_cust, file_name) old_location_comp_ = os.path.join( os.path.join(location, 'Company'), cust) old_location_comp = os.path.join(old_location_comp_, old) len_old = len(os.listdir(old_location_comp)) old_final_comp = os.path.join(old_location_comp, file_name) if len_old == 1: shutil.rmtree(old_location_comp) shutil.rmtree(old_location_cust) else: os.unlink(old_final_comp) os.unlink(old_final_cust) def view_windows(self): '''Used to re-initialize the totals and main window''' self.save_invoice() self.read_in_data() def closeEvent(self, event): if self.start_flag: self.save_invoice(printing=True) flag = self.save_no_threading() if flag == 0: reply = QMessageBox.question( self, 'Close Window', 'Do you want to close the application?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() else: event.ignore() else: event.accept() def updater(self): QMessageBox.information(self, 'Restart Required', 'Run BEI_Updater and Restart program', QMessageBox.Ok) self.close() def change_address(self): self.edi = EDI(self.font, self.size_policy, self.base_directory) def view_customer(self): flag = self.save_no_threading() if flag == 0: location = os.path.join(os.path.expanduser('~/Desktop'), 'BEI_Invoices') location = os.path.join(location, 'Customer') cust_location = os.path.join(location, self.customer.replace(' ', '_')) machine_location = os.path.join( cust_location, self.machine_text.replace(' ', '_')) job_location = os.path.join(machine_location, '{}.pdf'.format( self.current_job)).replace('&', '^&') print(job_location) subprocess.Popen(job_location, shell=True) else: pass def view_company(self): flag = self.save_no_threading() if flag == 0: location = os.path.join(os.path.expanduser('~/Desktop'), 'BEI_Invoices') location = os.path.join(location, 'Company') cust_location = os.path.join(location, self.customer.replace(' ', '_')) machine_location = os.path.join( cust_location, self.machine_text.replace(' ', '_')) job_location = os.path.join(machine_location, '{}.pdf'.format( self.current_job)).replace('&', '^&') subprocess.Popen(job_location, shell=True) else: pass def save_no_threading(self): self.save_invoice(printing=True) try: pdf2.PDF_Builder(self.current_job, self.base_directory, 'Company') pdf2.PDF_Builder(self.current_job, self.base_directory, 'Customer') return 0 except: QMessageBox.information(self, 'Opening Failure', 'Close file and try again', QMessageBox.Ok) time.sleep(1) return 1 def envelop_write(self): #navigate to the envelope folder loc = os.path.join( os.path.join(self.base_directory, 'Customer_Envelopes'), self.envelope_date + '.txt') f = open(loc, 'r') data = f.readlines() f.close() job_numbers = [] for i in data: job_numbers.append(i.split()[1]) QMessageBox.information( self, 'Envelope Printing', 'Load {} invoices into printer before clicking OK'.format( len(job_numbers)), QMessageBox.Ok) base = os.path.join(self.base_directory, 'Saved_Invoices') for i in range(len(job_numbers)): enve_loc = os.path.join(os.path.join(base, job_numbers[i]), 'envelope.pdf') os.startfile(enve_loc, 'print') def envelop_write1(self): #get the job number to print num, ok = QInputDialog.getText(self, 'Single Customer Envelope', 'Job Number to print:', QLineEdit.Normal, '') if num != '' and ok: writer = EWriter(self.base_directory, num) writer.generate_latex() QMessageBox.information( self, 'Envelope Printing', 'Load 1 invoices into printer before clicking OK', QMessageBox.Ok) writer.print_pdf() def billing_envelopes(self): self.billing_ = CE(self.base_directory)