def add_test_haul(self):
        """
        Method to add a test haul to the model + database
        :param haul: QJSValue - dictionary contained in a QJSValue object
        :return: None
        """
        # Add to the Database
        sql = "INSERT INTO HAULS('HAUL_NUMBER', 'START_DATETIME', 'END_DATETIME', 'PROCESSING_STATUS', 'IS_TEST') " + \
            "VALUES(?, ?, ?, ?, ?);"
        now = datetime.now()
        date = now.strftime("%m/%d/%Y")
        start = now
        start_time = start.strftime("%H:%M:%S")
        end = (now + timedelta(hours=1))
        end_time = end.strftime("%H:%M:%S")
        haul_number = "t" + str(round((now - datetime.utcfromtimestamp(0)).total_seconds() * 1000.0))

        # Get all Test Hauls - Adjust the last three digits to be 900 and greater so as to not conflict
        # with other haul numbers when we print specimen labels where we only keep the last three digits
        # of the haul
        test_hauls = Hauls.select(fn.substr(Hauls.haul_number, 12, 3).alias('test_haul_number'))\
            .where(Hauls.haul_number.contains("t"))\
            .order_by(fn.substr(Hauls.haul_number, 12, 3).desc())
        # for test_haul in test_hauls:
        #     logging.info('{0}'.format(test_haul.test_haul_number))

        try:
            last_test_haul_num = test_hauls.get().test_haul_number
            if int(last_test_haul_num) < 900:
                haul_last_three = "900"
            else:
                haul_last_three = str(int(last_test_haul_num) + 1)
        except DoesNotExist as dne:
            haul_last_three = "900"
        except Exception as ex:
            haul_last_three = "900"

        haul_number = haul_number[:-3] + haul_last_three

        # logging.info('last test haul num: {0} > {1}'.format(last_test_haul_num, haul_number))

        haul = {"haulNumber": haul_number, "date": date,
            "startTime": start_time, "endTime": end_time, "status": "Active", "isTest": "True"}

        params = [haul_number, start.isoformat(), end.isoformat(), "Active", "True"]
        self._db.execute(query=sql, parameters=params)
        haul_id = self._db.get_last_rowid()  # Return the primary key of the newly added record

        # Add to the Model - N.B. need to first get the newly added HAUL_ID and add that to haul
        haul["haulId"] = haul_id

        is_added = False
        for i in range(self.count):
            if "t" in self.get(i)["haulNumber"]:
                continue
            self.insertItem(i, haul)
            is_added = True
            break
        if not is_added:
            self.appendItem(haul)
    def _get_hauls_from_db(self, time_frame="today"):
        """
        Method to query the trawl_backdeck.db to retrieve all of the test hauls
        :return:
        """
        if time_frame not in ["today", "two days", "all"]:
            return
        adapter = {"today": 0, "two days": 1, "all": 1000}
        time_frame = adapter[time_frame]

        # Retrieve all test hauls from the database
        self._local_hauls = []

        # logging.info('timedelta: ' + str(timedelta(days=time_frame)))
        # start_datetime = (datetime.now() - timedelta(hours=48)).isoformat()
        start_datetime = (datetime.now().date() - timedelta(days=time_frame)).isoformat()
        # logging.info('start_datetime: ' + str(start_datetime))
        local_hauls = Hauls.select().where((Hauls.start_datetime >= start_datetime) | (Hauls.is_test == "True"))
        for haul in local_hauls:
            self._local_hauls.append(model_to_dict(haul))

        # self._local_hauls = sorted(self._local_hauls, key=lambda x: (x["haul_number"].isdigit(), x["haul_number"]))

        self._hauls_model.clear()
        self._add_model_items(hauls=self._local_hauls)
    def delete_test_haul(self, index):
        """
        Method to delete the test haul and associated catch_partition + specimen data from the DB
        :param index: int - representing the index location in the model
        :return:
        """
        if index is None or index == -1 or not isinstance(index, int):
            return

        item = self.get(index)
        status = item["status"]
        haul_id = item["haulId"]

        # Delete from the Model
        self.removeItem(index)

        # Update the state machine as appropriate
        if status == "Selected" or self.count == 0:
            self._app.state_machine.haul = None

        try:
            haul = Hauls.get(Hauls.haul == haul_id)
            haul.delete_instance(recursive=True, delete_nullable=True)

        except Exception as ex:
            pass
예제 #4
0
    def _get_operations_from_db(self, time_frame="today"):
        """
        Method to query the trawl_backdeck.db to retrieve all of the test hauls
        :return:
        """
        if time_frame not in ["today", "two days", "all"]:
            return
        adapter = {"today": 0, "two days": 1, "all": 1000}
        time_frame = adapter[time_frame]

        # Retrieve all test hauls from the database
        self._local_operations = []
        start_datetime = (datetime.now().date() - timedelta(days=time_frame)).isoformat()
        local_operations = Hauls.select().where((Hauls.start_datetime >= start_datetime) | (Hauls.is_test == "True"))
        for op in local_operations:
            self._local_operations.append(model_to_dict(op))

        self._operations_model.clear()
        self._add_model_items(operations=self._local_operations)
    def print_job(self, comport, pi_id, action, specimen_number):
        """
        Great reference + example code for printing using EPL commands:
        https://www.xtuple.org/node/1083

        EPL Reference:
        https://www.zebra.com/content/dam/zebra/manuals/en-us/printer/epl2-pm-en.pdf

        :return:
        """
        if self._printer_thread.isRunning():
            return

        if specimen_number is None:
            return

        # Line 1 - Header
        header = "NOAA/NWFSC/FRAM - WCGBT Survey"

        # Line 2a - Principal Investigator
        try:
            investigator = PrincipalInvestigatorLu.select() \
                .where(PrincipalInvestigatorLu.principal_investigator == pi_id).get().last_name
        except DoesNotExist as ex:
            investigator = "PI Not Available"

        # Line 2b - Action Type
        # action - that was passed in

        # Line 3 - Haul #
        haul_id = self._app.state_machine.haul["haul_number"]
        if "t" in haul_id and len(haul_id) > 3:
            haul_id = "t" + haul_id[-4:]

        # Line 4 - Species Scientific Name
        species = self._app.state_machine.species["scientific_name"]

        # Line 5 - Length / Weight / Sex
        try:
            length = weight = sex = stomach = tissue = ovary = testes = ""
            parent_specimen = self._app.state_machine.specimen[
                "parentSpecimenId"]
            specimens = (Specimen.select(Specimen, TypesLu).join(
                TypesLu,
                on=(Specimen.action_type == TypesLu.type_id
                    ).alias('types')).where(
                        Specimen.parent_specimen == parent_specimen))
            for specimen in specimens:
                if "length" in specimen.types.type.lower():
                    length = specimen.numeric_value
                elif "weight" in specimen.types.type.lower():
                    weight = round(specimen.numeric_value, 2)
                elif "sex" in specimen.types.type.lower():
                    sex = specimen.alpha_value
                elif "stomach" in specimen.types.type.lower():
                    stomach = specimen.alpha_value
                elif "tissue" in specimen.types.type.lower():
                    tissue = specimen.alpha_value
                elif "ovary" in specimen.types.type.lower():
                    ovary = specimen.alpha_value
                elif "testes" in specimen.types.type.lower():
                    testes = specimen.alpha_value
        except DoesNotExist as ex:
            pass
        except Exception as ex:
            logging.info('Error creating the measurement line: ' + str(ex))
        measurement = "Len: " + str(length) + "cm, Wt: " + str(
            weight) + "kg, Sex: " + str(sex)

        # Line 3B - Shortened Specimen Number - on the same line as the haul ID
        short_specimen_number = ""
        try:
            if investigator == "FRAM":
                print_iteration = ""
                specimen_number_split = specimen_number.split("-")
                if len(specimen_number_split) == 5:
                    vessel_id = specimen_number_split[1]
                    spec_num = specimen_number_split[4]
                    if not specimen_number[-1:].isdigit():
                        print_iteration = specimen_number[-1]
                    if stomach != "" or tissue != "":
                        short_specimen_number = vessel_id + spec_num + print_iteration
                    elif ovary != "" or testes != "":
                        short_specimen_number = vessel_id + haul_id + spec_num + print_iteration
                short_specimen_number = ", Short #: " + short_specimen_number
        except Exception as ex:
            logging.error(
                f"Error creating the shortened specimen number: {ex}")

        # Line 7 - Latitude / Longitude / Depth             # location = "47 15.54N, 126 27.55W"
        try:
            haul = Hauls.select().where(
                Hauls.haul == self._app.state_machine.haul["haul_id"]).get()
            haul_start = haul.start_datetime
            latitude = haul.latitude_min
            longitude = haul.longitude_min
            depth = haul.depth_min
            depth_uom = haul.depth_uom

            if isinstance(depth, float) and depth_uom == "ftm":
                depth = 1.8288 * depth
            if latitude and longitude and depth:
                location = f"{latitude:.6f}, {longitude:.6f}, {depth:.1f}m"
            else:
                location = f"{latitude:.6f}, {longitude:.6f}, Unknown"
        except Exception as ex:
            location = "Unknown, Unknown, Unknown"

        # Line 6 - Date/Time
        try:
            date = datetime.now().strftime(
                "%Y%m%d %H%M%S")  # date = "08/16/2015"
            date_year = datetime.now().year
            haul_dt = arrow.get(haul_start)
            haul_year = haul_dt.datetime.year
            logging.info(
                f"date_year={date_year}, haul_year={haul_year},     date={date} > haul_dt = {haul_dt}"
            )
            if date_year != haul_year:
                haul_dt = haul_dt.format('YYYYMMDD HH:mm:ss')
                if haul_year > date_year:
                    date = haul_dt
            logging.info(f"new date: {date}")

        except Exception as ex:
            logging.info(f"error getting the proper date/time: {ex}")

        # Line 8 - Specimen number
        # If no character at the end, add an A, other increase the character by 1 and update the list item
        if specimen_number[-1:].isdigit():
            specimen_number += "A"
        else:
            char = chr(ord(specimen_number[-1:]) + 1)
            specimen_number = str(specimen_number[:-1]) + char

        # TODO Todd Hay Update_list_item - should I call back to special_actions.upsert here?
        # self.update_list_item(action_type, specimen_number)
        self.tagIdChanged.emit(specimen_number)

        # Line 9 - barcode_number
        # barcode_number = re.sub(r'[^\d.]+', '', specimen_number)
        # barcode_number = re.sub(r'[\W]+', '', specimen_number)      # strips the hyphens
        # barcode_number = specimen_number

        # Strip all hypens and alpha characters
        barcode_number = re.sub(r'[^\d]', '', specimen_number)

        # TODO Todd Hay - I might need to strip the - from the barcode to have it get properly encoded
        # Per p. 54 - printer specification (epl2 programming manual), hyphens may be used but they'll be ignored
        # barcode_number = int(specimen_number.strip('-'))

        # logging.info('specimen number: ' + str(specimen_number))
        # logging.info('barcode number: ' + str(barcode_number))

        suffix = "\"\n"
        lead_in = """
N
O
q500
S3
D10
ZT\n"""
        lead_in_bytes = bytes(lead_in, "UTF-8")

        count = 1
        lead_out = "\nP" + str(
            count) + "\n\n"  # lead out sends the label count (number to print)
        lead_out_bytes = bytes(lead_out, "UTF-8")

        header_bytes = bytes("A0,10,0,4,1,1,N,\"" + header + suffix, "UTF-8")
        investigator_bytes = bytes(
            "A0,50,0,4,1,1,N,\"" + "PI: " + investigator + ", " + str(action) +
            suffix, "UTF-8")
        haul_id_bytes = bytes(
            "A0,90,0,4,1,1,N,\"" + "Haul ID: " + str(haul_id) +
            str(short_specimen_number) + suffix, "UTF-8")
        species_bytes = bytes(
            "A0,130,0,4,1,1,N,\"" + "Species: " + species + suffix, "UTF-8")
        measurement_bytes = bytes("A0,170,0,4,1,1,N,\"" + measurement + suffix,
                                  "UTF-8")
        date_bytes = bytes(
            "A0,210,0,4,1,1,N,\"" + "Date: " + str(date) + suffix, "UTF-8")
        location_bytes = bytes("A0,250,0,4,1,1,N,\"" + str(location) + suffix,
                               "UTF-8")
        specimen_number_bytes = bytes(
            "A0,290,0,4,1,1,N,\"" + "Spec #: " + str(specimen_number) + suffix,
            "UTF-8")
        barcode_bytes = bytes(
            "B0,330,0,1,3,3,72,N,\"" + str(barcode_number) + suffix, "UTF-8")

        rows = [
            lead_in_bytes, header_bytes, investigator_bytes, haul_id_bytes,
            species_bytes, measurement_bytes, date_bytes, location_bytes,
            specimen_number_bytes, barcode_bytes, lead_out_bytes
        ]

        if comport is None:
            comport = "COM9"

        kwargs = {"comport": comport, "rows": rows}

        self._printer_worker = PrinterWorker(kwargs=kwargs)
        self._printer_worker.moveToThread(self._printer_thread)
        self._printer_worker.printerStatus.connect(
            self._printer_status_received)
        self._printer_thread.started.connect(self._printer_worker.run)
        self._printer_thread.start()
    def run(self):

        self._is_running = True

        haul_data = []

        # Query the wheelhouse via the RpcServer for the daily hauls
        ip = self._app.settings.wheelhouseIpAddress
        port = self._app.settings.wheelhouseRpcServerPort
        logging.info('Wheelhouse RpcServer address: ' + str(ip) + ", " + str(port))

        real_hauls = []
        try:
            server = xrc.ServerProxy('http://' + ip + ':' + str(port), allow_none=True, use_builtin_types=True)
            real_hauls = server.get_hauls()
            logging.info('Number of hauls received from wheelhouse: ' + str(len(real_hauls)))

        except Exception as ex:
            logging.info('Error contacting wheelhouse computer: ' + str(ex))

        # template = ['haul_number', 'start_datetime', 'end_datetime', 'latitude_min', 'longitude_min', 'latitude_max', 'longitude_max',
        #           'depth_min', 'depth_max', 'vessel_name', 'vessel_color', 'pass_number', 'leg_number']
        # template = {x:None for x in template}

        # For the newly retrieve haul, insert into the database if the haul doesn't exist, otherwise get the haul
        for real_haul in real_hauls:
            # logging.info('real_haul: ' + str(real_haul))
            try:
                logging.info(f"real_haul: {real_haul}")
                logging.info(f"real_haul depth data: {real_haul['depth']}, {real_haul['depth_uom']}")
            except Exception as ex:
                logging.error(f"real haul depth data is blowing up: {ex}")

            current_haul, created = Hauls.get_or_create(haul_number=real_haul["haul_number"],
                                                        defaults={'start_datetime': real_haul["start_time"] if "start_time" in real_haul else None,
                                                                  'end_datetime': real_haul["end_time"] if "end_time" in real_haul else None,
                                                                  'latitude_min': real_haul["latitude"] if "latitude" in real_haul else None,
                                                                  'longitude_min': real_haul["longitude"] if "longitude" in real_haul else None,
                                                                  'latitude_max': real_haul["latitude"] if "latitude" in real_haul else None,
                                                                  'longitude_max': real_haul["longitude"] if "longitude" in real_haul else None,
                                                                  'depth_min': real_haul["depth"] if "depth" in real_haul else None,
                                                                  'depth_max': real_haul["depth"] if "depth" in real_haul else None,
                                                                  'depth_uom': real_haul["depth_uom"] if "depth_uom" in real_haul else None,
                                                                  'vessel_name': real_haul["vessel_name"] if "vessel_name" in real_haul else None,
                                                                  'vessel_color': real_haul["vessel_color"] if "vessel_color" in real_haul else None,
                                                                  'pass_number': real_haul["pass"] if "pass" in real_haul else None,
                                                                  'leg_number': real_haul["leg"] if "leg" in real_haul else None,
                                                                  'is_test': "False"})

            if created:
                Hauls.update(processing_status="Active").where(Hauls.haul_number == real_haul["haul_number"]).execute()
            else:
                if "start_time" in real_haul:
                    # logging.info('start > db / real_haul: ' + str(real_haul["haul_number"]) + ', '+ str(current_haul.start_datetime) + ' / ' + str(real_haul["start_time"]))

                    if current_haul.start_datetime != real_haul["start_time"]:
                        Hauls.update(start_datetime = real_haul["start_time"], end_datetime = None).where(Hauls.haul_number == real_haul["haul_number"]).execute()
                else:
                    Hauls.update(start_datetime=None).where(Hauls.haul_number == real_haul["haul_number"]).execute()
                if "end_time" in real_haul:
                    if current_haul.end_datetime != real_haul["end_time"]:
                        Hauls.update(end_datetime = real_haul["end_time"]).where(Hauls.haul_number == real_haul["haul_number"]).execute()
                    # logging.info('end > db / real_haul: ' + str(real_haul["haul_number"]) + ', ' + str(
                    #         current_haul.end_datetime) + ' / ' + str(real_haul["end_time"]))
                else:
                    Hauls.update(end_datetime=None).where(Hauls.haul_number == real_haul["haul_number"]).execute()


            current_haul = Hauls.get(haul_number=real_haul["haul_number"])

            haul_data.append(model_to_dict(current_haul))

        self._is_running = False
        self.haulsReceived.emit(haul_data)