예제 #1
0
    def get_quantity(self):
        """Compute the quantity according to the transactions attached to this medicine."""
        # Get latest Stock Count and then make the sum
        transactions = self.transactions.order_by("date")

        # Find last IN (type=1) or STOCK COUNT (type=8)
        last_stock_count = transactions.filter(
            transaction_type__in=[1, 8]).latest("date")
        # If found: filter by date (only recent transaction to take in account)
        # If not found: start from beginning
        if last_stock_count:
            transactions = self.transactions.filter(
                date__gte=last_stock_count.date).order_by("date")
        # Parse each transactions
        quantity = 0
        for transaction in transactions:
            if transaction.transaction_type in [1, 8]:
                quantity = transaction.value
            else:
                quantity -= transaction.value

        if quantity < 0:
            log.warning("Element with negative quantity")
            return 0
        return quantity
예제 #2
0
    def set_values(self):
        objects = []
        import itertools
        for item in itertools.product(SECTIONS.keys(), TYPES.keys(), WIDGETS):
            identifier = "-".join(item)
            obj = self.builder.get_object(identifier)
            if not obj:
                log.warning("Object `%s` not found", identifier)
                continue

            objects.append(obj)
            value = self.get_value(section=item[0], type=item[1])

            if item[-1] == "btn":
                obj.connect("clicked", self.show_detail, item)
                if not value:
                    obj.set_sensitive(False)
                else:
                    obj.set_sensitive(True)

            if item[-1] == "label":
                obj.set_text(str(value))

            if value > 0:
                obj.get_style_context().add_class("bold")
            else:
                obj.get_style_context().remove_class("bold")
예제 #3
0
    def search_click(self, source, item, item_type):
        """Open the related view of the item clicked."""
        if item_type not in self.actions.list_actions():
            log.warning("Action %s not registered.", item_type)
            return False

        self.actions.activate_action(item_type, GLib.Variant("i", item["id"]))
예제 #4
0
 def get_value(self, section, type):
     if section not in self.data:
         log.warning("Section `%s` not in `self.data`.", section)
         return 0
     if type not in self.data[section]:
         log.warning("Type `%s` not in `self.data['%s']`.", type, section)
         return 0
     return len(self.data[section][type])
예제 #5
0
    def contents(self, element):
        """Return `element` contents list."""
        if "medicines" in element:
            return element["medicines"]
        elif "articles" in element:
            return element["articles"]
        elif "contents" in element:
            return element["contents"]

        log.warning("Content not identified. Skipping. See debug log.")
        log.debug(element)
        return []
예제 #6
0
    def copy(self, source, output, param):
        section = param[0]
        type = param[1]

        if section not in self.data:
            log.warning("Section `%s` not in `self.data`.", section)
            return None
        if type not in self.data[section]:
            log.warning("Type `%s` not in `self.data['%s']`.", type, section)
            return None

        elements = self.data[section][type]

        header = get_header(output, section, type)

        parser = DataParser(elements, section, type, self.params)
        items = parser.get_items()

        if output == "txt":
            self.copy_as_txt(
                items=items,
                type=type,
                header=header
                )
        else:
            output = tempfile.NamedTemporaryFile(
                prefix="pharmaship_",
                suffix=".csv",
                delete=False
                )
            with open(output.name, "w", newline='') as csvfile:
                self.copy_as_csv(
                    items=items,
                    fields=header,
                    tmp_file=csvfile
                    )

            utils.open_file(output.name)
예제 #7
0
    def db_import(self, source, dialog):
        """Copy database from file to pharmaship database location."""
        filename = dialog.get_filename()
        if not filename:
            return False

        # Create a backup copy
        db_filename = settings.DATABASES['default']['NAME']
        bak_filename = db_filename + ".bak"

        shutil.copy(db_filename, bak_filename)

        # Overwrite the current database by the selected file
        try:
            shutil.copy(filename, db_filename)
        except shutil.SameFileError as error:
            log.warning("Using the same filename, so nothing to do. %s", error)

        self.params.refresh()

        dialog.destroy()
        self.success_dialog()
        return True
예제 #8
0
    def create_list_store(self, section, type):
        if section not in self.data:
            log.warning("Section `%s` not in `self.data`.", section)
            return None
        if type not in self.data[section]:
            log.warning("Type `%s` not in `self.data['%s']`.", type, section)
            return None

        # Name, quantity, exp-date, required_qty
        list_store = Gtk.ListStore(str, str, str)

        elements = self.data[section][type]

        parser = DataParser(elements, section, type, self.params)
        items = parser.get_items()

        for item in items:
            if type == "missing":
                list_store.append((
                    item["full_name"],
                    "{0}/{1}".format(item["current_quantity"], item["required_quantity"]),
                    str(item["missing_quantity"]),
                    ))
            elif type in ["perished", "warning"]:
                list_store.append((
                    item["full_name"],
                    str(item["quantity"]),
                    item["full_date"],
                ))
            elif type == "nc":
                list_store.append((
                    item["full_name"],
                    str(item["quantity"]),
                    item["full_nc"],
                ))

        return list_store
예제 #9
0
def parser_element(equipment, data, warning_delay,
                   today=datetime.date.today()):
    """Parse the database to render a list of Equipment > Article.

    :param models.Equipment equipment: Equipment to parse
    :param dict data: Common data for parsing. Following keys must be present:

        * ``qty_transactions``: QuerySet of \
        :class:`pharmaship.inventory.models.QtyTransaction`
        * ``locations``: formatted list of \
        :class:`pharmaship.inventory.models.Location`

    :param datetime.date warning_delay: Date from which warning flag must be \
    set
    :param datetime.date today: Date from which expired flag must be set.

    :return: Formatted information with articles.
    :rtype: dict
    """
    # ordered_items = data["ordered_items"]
    qty_transactions = data["qty_transactions"]
    locations = data["locations"]

    element_dict = {}
    element_dict['id'] = equipment.id
    element_dict['name'] = equipment.name
    element_dict['packaging'] = equipment.packaging
    element_dict['remark'] = equipment.remark
    element_dict['perishable'] = equipment.perishable
    element_dict['consumable'] = equipment.consumable
    element_dict['picture'] = equipment.picture

    element_dict['locations'] = []
    # Ordered
    # element_dict['ordered'] = 0
    # for item in ordered_items:
    #     if item.object_id == equipment.id:
    #         element_dict['ordered'] += item.quantity
    # Tags
    element_dict['tag'] = equipment.tag
    # Quantity
    element_dict['quantity'] = 0

    element_dict['articles'] = []
    element_dict['exp_dates'] = []
    element_dict['has_nc'] = False
    element_dict['has_date_warning'] = False
    element_dict['has_date_expired'] = False

    # Compute once the warning date from warning_delay days
    warning_date = today + datetime.timedelta(days=warning_delay)

    # Finding attached articles (Article)
    for article in equipment.articles.all():
        # Do not parse the used articles (quantity = 0)
        if article.used:
            continue
        item_dict = {}

        item_dict['id'] = article.id
        item_dict['name'] = article.name
        # Non conformity fields
        item_dict['nc_packaging'] = article.nc_packaging
        # Expiration date
        item_dict['exp_date'] = article.exp_date
        element_dict['exp_dates'].append(article.exp_date)
        # Check if the article is expired or not and if the expiry is within
        # the user-defined period
        # Consider "today" as already passed (that is why we use <= operator)
        item_dict['expired'] = False
        item_dict['warning'] = False
        if article.exp_date and article.exp_date <= warning_date:
            item_dict['warning'] = True
            element_dict['has_date_warning'] = True
        if article.exp_date and article.exp_date <= today:
            item_dict['expired'] = True
            element_dict['has_date_expired'] = True
        # Location

        # In case of unassigned location
        if article.location_id == 0:
            item_dict['location'] = {
                "sequence": [_("Unassigned")],
                "id": None,
                "parent": None
            }
            location_display = _("Unassigned")
        else:
            for item in locations:
                if article.location_id == item["id"]:
                    item_dict['location'] = item
                    location_display = " > ".join(item["sequence"])
                    if location_display not in element_dict['locations']:
                        element_dict['locations'].append(location_display)
        # Quantity
        item_dict['quantity'] = get_quantity(qty_transactions, article.id)

        if item_dict['quantity'] < 0:
            log.warning("Article (ID: %s) with negative quantity (%s)",
                        item_dict["id"], item_dict["quantity"])

        # Adding the article quantity to the equipment quantity
        if (equipment.perishable
                and article.exp_date > today) or (equipment.perishable
                                                  is not True):
            element_dict['quantity'] += item_dict['quantity']

        # Add the molecule_id in case of reverse search
        item_dict['equipment'] = {"id": equipment.id, "name": equipment.name}

        # Remark
        item_dict['remark'] = article.remark

        # Adding the article dict to the list
        element_dict['articles'].append(item_dict)

        # If article has a non-conformity, set element_dict.has_nc to True
        if article.nc_packaging:
            element_dict["has_nc"] = True

    # Returning the result dictionnary
    return element_dict
예제 #10
0
def parser_element(molecule, data, warning_delay, today):
    """Parse the database to render a list of Molecule > Medicine.

    :param models.Molecule molecule: Molecule to parse
    :param dict data: Common data for parsing. Following keys must be present:

        * ``qty_transactions``: QuerySet of \
        :class:`pharmaship.inventory.models.QtyTransaction`
        * ``locations``: formatted list of \
        :class:`pharmaship.inventory.models.Location`

    :param datetime.date warning_delay: Date from which warning flag must be \
    set
    :param datetime.date today: Date from which expired flag must be set.

    :return: Formatted information with medicines.
    :rtype: dict
    """
    # ordered_items = data["ordered_items"]
    qty_transactions = data["qty_transactions"]
    locations = data["locations"]

    element_dict = {}
    # ID
    element_dict['id'] = molecule.id
    # Name
    element_dict['name'] = molecule.name
    # Roa, Dosage_form, Composition
    element_dict['roa'] = molecule.get_roa_display()
    element_dict['dosage_form'] = molecule.get_dosage_form_display()
    element_dict['composition'] = molecule.composition

    element_dict['locations'] = []
    # Medicine_list
    if molecule.medicine_list:
        element_dict['medicine_list'] = molecule.get_medicine_list_display()
    # Remark
    element_dict['remark'] = molecule.remark
    # Ordered
    # element_dict['ordered'] = 0
    # for item in ordered_items:
    #     if item.object_id == molecule.id:
    #         element_dict['ordered'] += item.quantity
    # Tags
    element_dict['tag'] = molecule.tag
    # Quantity
    element_dict['quantity'] = 0

    element_dict['medicines'] = []
    element_dict['exp_dates'] = []

    element_dict['has_nc'] = False
    element_dict['has_date_warning'] = False
    element_dict['has_date_expired'] = False

    # Compute once the warning date from warning_delay days
    warning_date = today + datetime.timedelta(days=warning_delay)

    # Create the molecule name
    molecule_name_string = "{name} ({dosage_form} - {composition})".format(
        **element_dict)
    # Finding attached medicines (Medicine)
    for medicine in molecule.medicines.all():
        # Do not parse the used medicines (quantity = 0)
        if medicine.used:
            continue
        item_dict = {}
        # ID
        item_dict['id'] = medicine.id
        # Name
        item_dict['name'] = medicine.name
        # Non conformity fields
        item_dict['nc_composition'] = medicine.nc_composition
        item_dict['nc_molecule'] = medicine.nc_molecule
        # Expiration date
        item_dict['exp_date'] = medicine.exp_date
        element_dict['exp_dates'].append(medicine.exp_date)
        # Check if the medicine is expired or not and if the expiry is within
        # the user-defined period
        # Consider "today" as already passed (that is why we use <= operator)
        item_dict['expired'] = False
        item_dict['warning'] = False
        if medicine.exp_date <= warning_date:
            item_dict['warning'] = True
            element_dict['has_date_warning'] = True
        if medicine.exp_date <= today:
            item_dict['expired'] = True
            element_dict['has_date_expired'] = True
        # Location

        # In case of unassigned location
        if medicine.location_id == 0:
            item_dict['location'] = {
                "sequence": [_("Unassigned")],
                "id": None,
                "parent": None,
                "rescue_bag": None
            }
            location_display = _("Unassigned")
        else:
            for item in locations:
                if medicine.location_id == item["id"]:
                    item_dict['location'] = item
                    location_display = " > ".join(item["sequence"])
                    if location_display not in element_dict['locations']:
                        element_dict['locations'].append(location_display)
        # Quantity
        item_dict['quantity'] = get_quantity(qty_transactions, medicine.id)

        if item_dict['quantity'] < 0:
            log.warning("Medicine (ID: %s) with negative quantity (%s)",
                        item_dict["id"], item_dict["quantity"])

        # Adding the medicine quantity to the molecule quantity
        if medicine.exp_date > today:
            element_dict['quantity'] += item_dict['quantity']

        # Add the molecule_id in case of reverse search
        item_dict['molecule'] = {
            "id": molecule.id,
            "name": molecule_name_string
        }

        # Remark
        item_dict['remark'] = medicine.remark

        # Adding the medicine dict to the list
        element_dict['medicines'].append(item_dict)

        # If medicine has a non-conformity, set element_dict.has_nc to True
        if medicine.nc_composition or medicine.nc_molecule:
            element_dict["has_nc"] = True

    # Returning the result dictionnary
    return element_dict