Ejemplo n.º 1
0
def search(text, params):
    """Return the search results from a long enough text.

    To avoid unnecessary search, text length must be at least 2 chars.

    The method searches into medicines, equipment, laboratory and telemedical
    sets.

    The results are sorted by "parent" (Molecule/Equipment) and contains
    required quantities for each set if any, current quantity, group
    (MoleculeGroup or EquipmentGroup) and other names previously encountered
    (in Medicine and Article records).

    :param str text: String to search in the different database models.
    :param object params: Global Parameters of the application \
    (:class:`pharmaship.gui.view.GlobalParameters`)

    :return: List of parsed results. See ``pharmaship/schemas/search.json`` \
    for details.
    :rtype: list
    """
    if len(text) < 2:
        return []

    result = []

    result += get_molecules(text,  params)

    result += get_equipments(text, params)

    query_count_all()

    return result
Ejemplo n.º 2
0
    def response_use(self, source, dialog, article, builder):
        # Get response
        quantity_obj = builder.get_object("quantity")
        quantity = quantity_obj.get_value()

        if quantity < 0:
            return False

        if quantity == 0:
            # Nothing to do
            dialog.destroy()
            return

        # Get the object
        article_obj = models.Article.objects.get(id=article['id'])
        if article["quantity"] == quantity:
            article_obj.used = True
            article_obj.save()

        models.QtyTransaction.objects.create(transaction_type=2,
                                             value=quantity,
                                             content_object=article_obj)

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 3
0
    def dialog_modify(self, source, data):
        builder = Gtk.Builder.new_from_file(utils.get_template("location_add.glade"))
        dialog = builder.get_object("dialog")

        location_combo = builder.get_object("parent")

        utils.location_combo(
            location_combo,
            locations=self.params.locations,
            active=data["parent"],
            empty=True,
            exclude=[data["id"]]
            )

        name = builder.get_object("name")
        name.set_text(data["sequence"][-1])

        btn_modify = builder.get_object("btn_response")
        btn_modify.set_label(_("Modify this location"))

        builder.connect_signals({
            "on-response": (self.response_modify, data["id"], dialog, builder),
            "on-cancel": (utils.dialog_destroy, dialog)
        })

        query_count_all()

        dialog.set_transient_for(self.window)
        dialog.run()

        dialog.destroy()
Ejemplo n.º 4
0
def export_pdf(html_string, filename):
    """Export the equipment inventory in PDF."""
    css_path = os.path.join(settings.PHARMASHIP_REPORTS, filename)
    try:
        with open(css_path, "r") as fdesc:
            css_string = fdesc.read()
    except IOError as error:
        log.error("CSS file not readable: %s", error)
        return None

    # Create a temporary file
    tmp_file = tempfile.NamedTemporaryFile(prefix="pharmaship_",
                                           suffix=".pdf",
                                           delete=False)

    font_config = FontConfiguration()
    html = HTML(string=html_string)
    css = CSS(string=css_string, font_config=font_config)
    html.write_pdf(target=tmp_file.name,
                   stylesheets=[css],
                   font_config=font_config)

    query_count_all()

    return tmp_file.name
Ejemplo n.º 5
0
    def get_telemedical(self):
        result = {
            "missing": [],
            "perished": [],
            "warning": [],
            "nc": []
        }

        data = parsers.telemedical.parser(self.params)

        for element in data:
            if element["has_nc"]:
                result["nc"].append(element)
            if element["required_quantity"] > element["quantity"]:
                result["missing"].append(element)
            if element["has_date_expired"]:
                result["perished"].append(element)
                continue
            if element["has_date_warning"]:
                result["warning"].append(element)
                continue

        self.data["telemedical"] = result

        query_count_all()
Ejemplo n.º 6
0
    def get_molecules(self):
        result = {
            "missing": [],
            "perished": [],
            "warning": [],
            "nc": []
        }

        data = parsers.medicines.parser(self.params)

        for group in data:
            for element in data[group]:
                if element["has_nc"]:
                    result["nc"].append(element)
                if element["required_quantity"] > element["quantity"]:
                    result["missing"].append(element)
                if element["has_date_expired"]:
                    result["perished"].append(element)
                    continue
                if element["has_date_warning"]:
                    result["warning"].append(element)
                    continue

        self.data["molecules"] = result

        query_count_all()
Ejemplo n.º 7
0
    def get_first_aid_kit(self):
        result = {
            "missing": [],
            "perished": [],
            "warning": [],
            "nc": []
        }

        data = parsers.first_aid.parser(self.params)

        for kit in data:
            for element in kit["elements"]:
                if element["has_nc"]:
                    result["nc"].append(element)
                if element["required_quantity"] > element["quantity"]:
                    result["missing"].append(element)
                if element["has_date_expired"]:
                    result["perished"].append(element)
                    continue
                if element["has_date_warning"]:
                    result["warning"].append(element)
                    continue

        self.data["first_aid_kit"] = result

        query_count_all()
Ejemplo n.º 8
0
    def response_modify(self, source, location_id, dialog, builder):
        fields = {
            "entry": [
                "name"
            ],
            "combobox": [
                "parent"
            ]
        }

        cleaned_data = utils.get_form_data(LocationForm, builder, fields)
        if cleaned_data is None:
            return

        if cleaned_data["parent_id"] == 0:
            cleaned_data["parent_id"] = None

        location = Location.objects.get(id=location_id)
        location.name = cleaned_data["name"]
        location.parent_id = cleaned_data["parent_id"]
        location.save()

        dialog.destroy()
        self.refresh_grid()

        query_count_all()
Ejemplo n.º 9
0
    def response_add(self, source, dialog, builder):
        fields = {
            "entry": [
                "name"
            ],
            "combobox": [
                "parent"
            ]
        }

        cleaned_data = utils.get_form_data(LocationForm, builder, fields)
        if cleaned_data is None:
            return

        if cleaned_data["parent_id"] == 0:
            cleaned_data["parent_id"] = None

        Location.objects.create(
            parent_id=cleaned_data["parent_id"],
            name=cleaned_data["name"]
        )

        dialog.destroy()
        self.refresh_grid()

        query_count_all()
Ejemplo n.º 10
0
    def dialog_add(self, source, item):
        builder = Gtk.Builder.new_from_file(utils.get_template("subitem_add.glade"))
        dialog = builder.get_object("dialog")

        combobox = builder.get_object("item")
        self.subitem_combobox(combobox, item)
        combobox.connect("changed", self.combobox_changed, builder)

        remaining = builder.get_object("remaining")

        quantity = builder.get_object("quantity")
        quantity.connect("changed", self.quantity_changed, remaining)

        quantity_adjustment = builder.get_object("quantity_adjustment")
        quantity_adjustment.set_lower(0)

        remaining_adjustment = builder.get_object("remaining_adjustment")
        remaining_adjustment.set_lower(0)

        # Connect signals
        builder.connect_signals({
            "on-response": (self.response_add, dialog, item, builder),
            "on-cancel": (utils.dialog_destroy, dialog)
        })

        query_count_all()

        dialog.set_transient_for(self.window)
        dialog.run()

        dialog.destroy()
Ejemplo n.º 11
0
    def build_kits(self, kits=None):
        data = parser(self.params, kits)
        query_count_all()

        for kit in data:
            # Create a page
            child_builder = Gtk.Builder.new_from_file(utils.get_template("first_aid_kit.glade"))
            # child = child_builder.get_object("main-box")
            child = child_builder.get_object("child-scrolled")

            child_builder.connect_signals({
                "btn-save-clicked": (self.save_kit, child_builder, kit),
                "btn-cancel-clicked": (self.cancel, child_builder),
                "btn-modify-clicked": (self.enable_modify, child_builder)
            })

            name = child_builder.get_object("name")
            name.set_text(kit["name"])
            name.set_sensitive(False)

            location_combo = child_builder.get_object("location")
            location_combo.set_sensitive(False)
            utils.location_combo(
                combo=location_combo,
                locations=self.params.locations,
                active=kit["location_id"]
                )

            btn_save = child_builder.get_object("btn-save")
            btn_save.hide()

            self.toggled[kit["id"]] = False
            self.build_grid(child_builder, kit)
            self.stack.add_titled(child, "first-aid-kit-{0}".format(kit["id"]), kit["name"])
            self.children[kit["id"]] = child_builder
Ejemplo n.º 12
0
    def response_add(self, source, dialog, equipment, builder):
        fields = {
            "entry": ["name", "exp_date", "nc_packaging", "remark"],
            "combobox": ["location"],
            "spinbutton": ["quantity"],
            "textview": []
        }

        data = {"parent_id": equipment["id"]}

        cleaned_data = utils.get_form_data(forms.AddArticleForm, builder,
                                           fields, data)
        if cleaned_data is None:
            return

        # Add the article
        article = models.Article.objects.create(
            name=cleaned_data['name'],
            exp_date=cleaned_data['exp_date'],
            location_id=cleaned_data['location_id'],
            nc_packaging=cleaned_data['nc_packaging'],
            parent_id=cleaned_data['parent_id'],
            remark=cleaned_data['remark'])
        # Add the quantity
        models.QtyTransaction.objects.create(transaction_type=1,
                                             value=cleaned_data["quantity"],
                                             content_object=article)

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 13
0
    def response_delete(self, source, location_id, dialog, builder):
        location = Location.objects.get(id=location_id)
        location.delete()
        Location.objects.rebuild()

        dialog.destroy()
        self.refresh_grid()

        query_count_all()
Ejemplo n.º 14
0
    def dialog_add(self, source, equipment):
        builder = Gtk.Builder.new_from_file(
            utils.get_template("article_add.glade"))
        dialog = builder.get_object("dialog")

        label = builder.get_object("equipment")
        label.set_text("{0} ({1})".format(equipment["name"],
                                          equipment["packaging"]))

        # Check if equipment has previous locations to input the latest one as
        # default to ease the input
        active_location = None
        equipment_obj = models.Equipment.objects.get(id=equipment["id"])
        try:
            latest_article = equipment_obj.articles.latest("exp_date")
        except models.Article.DoesNotExist:
            latest_article = None
        # except ObjectDoesNotExist:
        #     latest_article = None

        if latest_article:
            active_location = latest_article.location.id
            log.debug("Found last location: %s", active_location)
        location_combo = builder.get_object("location")
        utils.location_combo(combo=location_combo,
                             locations=self.params.locations,
                             active=active_location)

        # By default name = equipment name
        name = builder.get_object("name")
        name.set_text(equipment["name"])

        # Expiry date input mask workaround
        exp_date = builder.get_object("exp_date_raw")
        exp_date = utils.grid_replace(exp_date,
                                      widgets.EntryMasked(mask=DATE_MASK))
        # exp_date.connect("activate", self.response_add, dialog, equipment, builder)
        builder.expose_object("exp_date", exp_date)

        # Connect signals
        # builder.connect_signals({
        #     "on_entry_activate": (self.response_add, dialog, equipment, builder)
        # })

        builder.connect_signals({
            "on-response": (self.response_add, dialog, equipment, builder),
            "on-cancel": (utils.dialog_destroy, dialog)
        })

        query_count_all()

        dialog.set_transient_for(self.window)
        dialog.run()

        dialog.destroy()
Ejemplo n.º 15
0
    def dialog_add(self, source, molecule):
        builder = Gtk.Builder.new_from_file(
            utils.get_template("medicine_add.glade"))
        dialog = builder.get_object("dialog")

        label = builder.get_object("molecule")
        label.set_text("{0} ({1} - {2})".format(molecule["name"],
                                                molecule["dosage_form"],
                                                molecule["composition"]))

        # Check if molecule has previous locations to input the latest one as
        # default to ease the input
        active_location = None
        molecule_obj = models.Molecule.objects.get(id=molecule["id"])
        try:
            latest_medicine = molecule_obj.medicines.latest("exp_date")
        except models.Medicine.DoesNotExist:
            latest_medicine = None

        if latest_medicine:
            active_location = latest_medicine.location.id
            log.debug("Found last location: %s", active_location)
        location_combo = builder.get_object("location")
        utils.location_combo(combo=location_combo,
                             locations=self.params.locations,
                             active=active_location)

        # By default name = molecule name
        name = builder.get_object("name")
        name.set_text(molecule["name"])

        # Expiry date input mask workaround
        exp_date = builder.get_object("exp_date_raw")
        exp_date = utils.grid_replace(exp_date,
                                      widgets.EntryMasked(mask=DATE_MASK))
        # exp_date.connect("activate", self.response_add, dialog, molecule, builder)
        builder.expose_object("exp_date", exp_date)

        # Connect signals
        builder.connect_signals({
            # "on-entry-activate": (self.response_add, dialog, molecule, builder),
            "on-response": (self.response_add, dialog, molecule, builder),
            "on-cancel": (utils.dialog_destroy, dialog)
        })

        query_count_all()

        dialog.set_transient_for(self.window)
        dialog.run()

        dialog.destroy()
Ejemplo n.º 16
0
    def build_grid(self):

        self.grid = Gtk.Grid()
        self.scrolled.add(self.grid)

        # Header
        label = Gtk.Label(_("Location"), xalign=0)
        label.set_hexpand(True)
        label.get_style_context().add_class("header-cell")
        self.grid.attach(label, 0, 0, 1, 1)

        # Add location button on header bar
        box = Gtk.Box()
        box.get_style_context().add_class("header-cell-box")
        btn = Gtk.Button(_("New Location"))
        btn.set_relief(Gtk.ReliefStyle.NONE)
        btn.get_style_context().add_class("header-cell-btn")
        btn.connect("clicked", self.dialog_add)
        box.add(btn)
        self.grid.attach(box, 1, 0, 1, 1)

        location_list = self.params.locations

        i = 0
        for item in location_list:
            i += 1

            prefix = "\t"*(len(item["sequence"]) - 1)
            label_string = "{0}{1}".format(prefix, item["sequence"][-1])

            label = Gtk.Label(label_string, xalign=0)
            label.get_style_context().add_class("medicine-item-cell")
            if item["rescue_bag"]:
                label.get_style_context().add_class("rescue-bag-item")
            elif item["id"] < 100:
                label.get_style_context().add_class("location-reserved-item")
            self.grid.attach(label, 0, i, 1, 1)

            # We cannot destroy a rescue bag tagged location
            if not item["rescue_bag"]:
                self.location_row_buttons(item, i)
            else:
                label = Gtk.Label("")
                label.get_style_context().add_class("medicine-item-buttons")
                self.grid.attach(label, 1, i, 1, 1)

            # Check if it is a top level item
            if len(item["sequence"]) == 1:
                label.get_style_context().add_class("location-parent")

        query_count_all()
Ejemplo n.º 17
0
    def update_rescue_bag_model(self, treeview):
        self.rescue_bag_store = Gtk.ListStore(str, bool, int)

        # Get allowance data
        rescue_bag_list = RescueBag.objects.all().order_by("name")

        for item in rescue_bag_list:
            # Append to the ListStore
            self.rescue_bag_store.append((item.name, False, item.id))

        treeview.set_model(self.rescue_bag_store)
        treeview.show_all()

        query_count_all()
Ejemplo n.º 18
0
    def update_model(self):
        treeview = self.builder.get_object("allowance-treeview")

        self.list_store = Gtk.ListStore(str, str, str, bool, int)

        # Get allowance data
        allowance_list = Allowance.objects.exclude(id=0).order_by("name")

        for item in allowance_list:
            self.list_store.append(
                (item.name, item.version, item.author, item.active, item.id))

        treeview.set_model(self.list_store)

        query_count_all()
Ejemplo n.º 19
0
    def do_activate(self):
        # We only allow a single window and raise any existing ones
        if not self.window:
            # Windows are associated with the application
            # when the last one is closed the application shuts down
            self.window = AppWindow(application=self,
                                    params=self.params,
                                    actions=self)
            self.window.set_size_request(800, 600)

        self.on_dashboard(None, None)
        self.window.show_all()

        query_count_all()
        log.info("Initialization completed!")
Ejemplo n.º 20
0
    def response_delete(self, source, dialog, builder, count):
        # Get selected RescueBag ID to delete
        to_delete = []
        for row in self.rescue_bag_store:
            if row[1]:
                to_delete.append(row[2])

        if len(to_delete) != count:
            return

        rescue_bags = RescueBag.objects.filter(
            id__in=to_delete).prefetch_related("location")

        for rescue_bag in rescue_bags:
            rescue_bag.location.delete()
            rescue_bag.delete()

        query_count_all()
        dialog.destroy()
        return True
Ejemplo n.º 21
0
    def response_modify(self, source, dialog, medicine, builder):
        fields = {
            "entry":
            ["name", "exp_date", "nc_composition", "nc_molecule", "remark"],
            "combobox": ["location"],
            "spinbutton": ["quantity"],
            "textview": []
        }

        cleaned_data = utils.get_form_data(forms.ModifyMedicineForm, builder,
                                           fields)
        if cleaned_data is None:
            return

        # Add the medicine
        medicine_obj = models.Medicine.objects.get(id=medicine['id'])
        medicine_obj.name = cleaned_data['name']
        medicine_obj.exp_date = cleaned_data['exp_date']
        medicine_obj.location_id = cleaned_data['location_id']
        medicine_obj.remark = cleaned_data['remark']

        # if cleaned_data['nc_composition']:
        medicine_obj.nc_composition = cleaned_data['nc_composition']
        # if cleaned_data['nc_molecule']:
        medicine_obj.nc_molecule = cleaned_data['nc_molecule']

        medicine_obj.save()

        if cleaned_data["quantity"] != medicine['quantity']:
            # Add the quantity (transaction type STOCK COUNT)
            models.QtyTransaction.objects.create(
                transaction_type=8,
                value=cleaned_data["quantity"],
                content_object=medicine_obj)

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 22
0
    def response_modify(self, source, dialog, item, perishable, builder):
        fields = {
            "entry": [
                "exp_date",
                "remark",
                "nc"
            ],
            "spinbutton": [
                "quantity"
            ]
        }

        data = {
            "perishable": perishable
        }

        cleaned_data = utils.get_form_data(forms.ModifySubitemForm, builder, fields, data)
        if cleaned_data is None:
            return

        item_obj = models.FirstAidKitItem.objects.get(id=item["id"])
        item_obj.exp_date = cleaned_data["exp_date"]
        item_obj.remark = cleaned_data["remark"]
        item_obj.nc = cleaned_data["nc"]
        item_obj.save()

        if cleaned_data["quantity"] != item['quantity']:
            # Add the quantity (transaction type STOCK COUNT)
            models.QtyTransaction.objects.create(
                transaction_type=8,
                value=cleaned_data["quantity"],
                content_object=item_obj
                )

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 23
0
    def dialog_delete(self, total):
        # Check the real number of RescueBag instances to delete
        current = RescueBag.objects.count()
        count = current - total
        if count <= 0:
            log.debug(
                "Number of RescueBag in database is high than requested.")
            return

        builder = Gtk.Builder.new_from_file(
            get_template("rescue_bag_dialog.glade"))
        dialog = builder.get_object("dialog")

        # Set message (showing remaining rescue bags to select for deletion)
        # Adapt for plural form
        label = builder.get_object("label")
        btn = builder.get_object("btn-delete")
        if count < 2:
            msg_text = _("Select the rescue bag to delete.")
            btn.set_label(_("Delete this rescue bag"))
        else:
            msg_text = _("Select the {0} rescue bags to delete.")
            btn.set_label(_("Delete these rescue bags"))
        label.set_text(msg_text.format(count))

        # Create the Treeview
        self.build_rescue_bag_tree(builder, count)

        # Connect signals
        builder.connect_signals({
            "on-response": (self.response_delete, dialog, builder, count),
            "on-cancel": (self.dialog_destroy, dialog),
        })

        query_count_all()

        dialog.run()

        dialog.destroy()
Ejemplo n.º 24
0
    def response_delete(self, source, dialog, item, builder):
        invalid = False
        # Get response
        reason_combo = builder.get_object("reason")
        reason = utils.get_reason(reason_combo)

        if reason is None:
            reason_combo.get_style_context().add_class("error-combobox")
            invalid = True

        if invalid:
            return

        # Get the object
        item_obj = models.FirstAidKitItem.objects.get(id=item['id'])

        # Reason is Other (error during input ?)
        if reason == 9:
            item_obj.delete()

        # Reason is Perished - it is one way to declare as perished, other way
        # is to "use" the medicine
        if reason == 4:
            item_obj.used = True
            item_obj.save()

            models.QtyTransaction.objects.create(
                transaction_type=4,
                value=0,
                content_object=item_obj
            )

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 25
0
def required_quantity(data, tar, allowance):
    """Update the required quantities for deserialized items.

    After successful deserialization, delete all related required quantity for
    the selected allowance. Then create all deserialized objects.

    :param dict data: Dictionnary with filename and model related. The \
    following keys must be present:

      * ``filename``: the name of the JSON file to extract from the tar \
      archive;
      * ``model``: the class of model to deserialize \
      (ie: :class:`pharmaship.inventory.models.MoleculeReqQty`).

    :param tarfile.TarFile tar: tar file archive containing the file to extract
    :param allowance: allowance instance to rattach
    :type allowance: models.Allowance

    :return: ``True`` if there is no error, ``False`` otherwise.
    :rtype: bool
    """
    log.debug("Updating required quantities for %s", data["filename"])

    deserialized_list = deserialize_json_file(data, tar, allowance)

    if deserialized_list is False:
        log.error("Error when deserializing file: %s", data["filename"])
        return False

    # As we are sure that the deserialization went fine,
    # delete all required quantities entry and create new ones
    data["model"].objects.filter(allowance_id__in=(0, allowance.id)).delete()

    data["model"].objects.bulk_create(deserialized_list)
    log.debug("Created %s instances", len(deserialized_list))
    query_count_all()

    return True
Ejemplo n.º 26
0
    def dialog_add(self, source):
        log.debug("Add location")

        builder = Gtk.Builder.new_from_file(utils.get_template("location_add.glade"))
        dialog = builder.get_object("dialog")

        location_combo = builder.get_object("parent")
        utils.location_combo(
            location_combo,
            locations=self.params.locations,
            empty=True
            )

        builder.connect_signals({
            "on-response": (self.response_add, dialog, builder),
            "on-cancel": (utils.dialog_destroy, dialog)
        })

        query_count_all()

        dialog.set_transient_for(self.window)
        dialog.run()

        dialog.destroy()
Ejemplo n.º 27
0
    def response_modify(self, source, dialog, article, builder):
        fields = {
            "entry": ["name", "exp_date", "nc_packaging", "remark"],
            "combobox": ["location"],
            "spinbutton": ["quantity"]
        }

        cleaned_data = utils.get_form_data(forms.ModifyArticleForm, builder,
                                           fields)
        if cleaned_data is None:
            return

        # Add the article
        article_obj = models.Article.objects.get(id=article['id'])
        article_obj.name = cleaned_data['name']
        article_obj.exp_date = cleaned_data['exp_date']
        article_obj.location_id = cleaned_data['location_id']
        article_obj.remark = cleaned_data['remark']

        article_obj.nc_packaging = cleaned_data['nc_packaging']

        article_obj.save()

        if cleaned_data["quantity"] != article['quantity']:
            # Add the quantity (transaction type STOCK COUNT)
            models.QtyTransaction.objects.create(
                transaction_type=8,
                value=cleaned_data["quantity"],
                content_object=article_obj)

        query_count_all()

        # At the end only
        dialog.destroy()
        # Refresh the list!
        self.refresh_grid()
Ejemplo n.º 28
0
def serialize_allowance(allowance, content_types):
    """Export an allowance using the YAML format.

    To have an usable export, the broadcaster needs:
        - the :model:`pharmaship.inventory.Allowance` selected instance,
    And related to this instance:
        - the :model:`pharmaship.inventory.Molecule` objects list,
        - the :model:`pharmaship.inventory.Equipment` objects list,
        - the :model:`pharmaship.inventory.MoleculeReqQty` objects list,
        - the :model:`pharmaship.inventory.EquipmentReqQty` objects list,
        - the :model:`pharmaship.inventory.RescueBagReqQty` objects list,
        - the :model:`pharmaship.inventory.FirstAidKitReqQty` objects list,
        - the :model:`pharmaship.inventory.TelemedicalReqQty` objects list,
        - the :model:`pharmaship.inventory.LaboratoryReqQty` objects list.

    Returns a list of filenames and streams.
    """
    log.debug("Start serialize")

    renderer = JSONRenderer()
    # Molecules used by the allowance
    molecule_id_list = []
    equipment_id_list = []

    # Required quantities for molecules
    molecule_reqqty_list = pharmaship.inventory.models.MoleculeReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    molecule_id_list += molecule_reqqty_list.values_list("base_id", flat=True)
    # molecule_reqqty_data = serializers.serialize(
    #     "yaml",
    #     molecule_reqqty_list,
    #     fields=('base', 'required_quantity'),
    #     use_natural_foreign_keys=True
    #     )
    # query_count_all()

    serialized = pharmaship.inventory.serializers.MoleculeReqQtySerializer(molecule_reqqty_list, many=True)
    molecule_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()

    # Required quantities for equipments
    equipment_reqqty_list = pharmaship.inventory.models.EquipmentReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    equipment_id_list += equipment_reqqty_list.values_list("base_id", flat=True)
    # equipment_reqqty_data = serializers.serialize(
    #     "yaml",
    #     equipment_reqqty_list,
    #     fields=('base', 'required_quantity'),
    #     use_natural_foreign_keys=True
    #     )
    # query_count_all()

    serialized = pharmaship.inventory.serializers.EquipmentReqQtySerializer(equipment_reqqty_list, many=True)
    equipment_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()

    # Required quantities for Laboratory
    laboratory_reqqty_list = pharmaship.inventory.models.LaboratoryReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    equipment_id_list += laboratory_reqqty_list.values_list("base_id", flat=True)
    # laboratory_reqqty_data = serializers.serialize(
    #     "yaml",
    #     laboratory_reqqty_list,
    #     fields=('base', 'required_quantity'),
    #     use_natural_foreign_keys=True
    #     )
    # query_count_all()

    serialized = pharmaship.inventory.serializers.LaboratoryReqQtySerializer(laboratory_reqqty_list, many=True)
    laboratory_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()


    # Required quantities for Telemedical
    telemedical_reqqty_list = pharmaship.inventory.models.TelemedicalReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    equipment_id_list += telemedical_reqqty_list.values_list("base_id", flat=True)
    # telemedical_reqqty_data = serializers.serialize(
    #     "yaml",
    #     telemedical_reqqty_list,
    #     fields=('base', 'required_quantity'),
    #     use_natural_foreign_keys=True
    #     )
    # query_count_all()

    serialized = pharmaship.inventory.serializers.TelemedicalReqQtySerializer(telemedical_reqqty_list, many=True)
    telemedical_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()

    # Required quantities for First Aid Kit
    first_aid_kit_reqqty_list = pharmaship.inventory.models.FirstAidKitReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    molecule_id_list += first_aid_kit_reqqty_list.filter(
        content_type_id=content_types["molecule"]
        ).values_list("object_id", flat=True)
    equipment_id_list += first_aid_kit_reqqty_list.filter(
        content_type_id=content_types["equipment"]
        ).values_list("object_id", flat=True)

    serialized = pharmaship.inventory.serializers.FirstAidKitReqQtySerializer(first_aid_kit_reqqty_list, many=True)
    first_aid_kit_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()

    # Required quantities for Rescue Bag
    rescue_bag_reqqty_list = pharmaship.inventory.models.RescueBagReqQty.objects.filter(allowance__in=[allowance]).prefetch_related("base")
    molecule_id_list += rescue_bag_reqqty_list.filter(
        content_type_id=content_types["molecule"]
        ).values_list("object_id", flat=True)
    equipment_id_list += rescue_bag_reqqty_list.filter(
        content_type_id=content_types["equipment"]
        ).values_list("object_id", flat=True)

    serialized = pharmaship.inventory.serializers.RescueBagReqQtySerializer(rescue_bag_reqqty_list, many=True)
    rescue_bag_reqqty_data = renderer.render(
        data=serialized.data,
        accepted_media_type='application/json; indent=2'
        )
    query_count_all()

    # Equipment used by the allowance
    equipment_list = pharmaship.inventory.models.Equipment.objects.filter(id__in=equipment_id_list).prefetch_related("group")
    equipment_data = serializers.serialize(
        "yaml",
        equipment_list,
        use_natural_foreign_keys=True,
        fields=("name", "packaging", "consumable", "perishable", "picture", "group", "remark")
        )
    log.debug("Equipment")
    query_count_all()

    # Molecule used by the allowance
    molecule_list = pharmaship.inventory.models.Molecule.objects.filter(id__in=molecule_id_list).prefetch_related("group")
    molecule_data = serializers.serialize(
        "yaml",
        molecule_list,
        use_natural_foreign_keys=True,
        fields=("name", "roa", "dosage_form", "composition", "medicine_list", "group", "remark")
        )
    log.debug("Molecule")
    query_count_all()

    # Allowance record
    allowance_data = serializers.serialize(
        "yaml",
        (allowance,),
        fields=('name', 'author', 'version', 'date', 'additional'),
        use_natural_foreign_keys=True
        )
    log.debug("Allowance")
    query_count_all()

    log.debug("End serialize")

    # Returning a list with tuples: (filename, data)
    return ([
        ('inventory/molecule_obj.yaml', remove_yaml_pk(molecule_data)),
        ('inventory/equipment_obj.yaml', remove_yaml_pk(equipment_data)),

        ('inventory/molecule_reqqty.json', molecule_reqqty_data),
        ('inventory/equipment_reqqty.json', equipment_reqqty_data),

        ('inventory/laboratory_reqqty.json', laboratory_reqqty_data),
        ('inventory/telemedical_reqqty.json', telemedical_reqqty_data),

        ('inventory/first_aid_kit_reqqty.json', first_aid_kit_reqqty_data),
        ('inventory/rescue_bag_reqqty.json', rescue_bag_reqqty_data),

        ('inventory/allowance.yaml', remove_yaml_pk(allowance_data)),
    ], equipment_list)
Ejemplo n.º 29
0
    def create_grid(self, toggle_row_num=None):
        grid = Gtk.Grid()

        # Header
        label = Gtk.Label(_("Name"), xalign=0)
        label.set_hexpand(True)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 0, 0, 1, 1)
        label = Gtk.Label(_("Remarks"), xalign=0)
        label.set_hexpand(True)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 1, 0, 1, 1)
        label = Gtk.Label(_("Packaging"), xalign=0)
        label.set_hexpand(True)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 2, 0, 1, 1)
        label = Gtk.Label(_("Location"), xalign=0)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 3, 0, 1, 1)
        label = Gtk.Label(_("Expiry"), xalign=0.5)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 4, 0, 1, 1)
        label = Gtk.Label(_("Quantity"), xalign=0.5)
        label.get_style_context().add_class("header-cell")
        grid.attach(label, 5, 0, 1, 1)

        label = Gtk.Label("", xalign=0)
        label.get_style_context().add_class("header-cell")
        # Size request because by default the colum content is "hidden"
        label.set_size_request(125, -1)
        grid.attach(label, 6, 0, 1, 1)

        data = parser(self.params)

        i = 0
        toggle_equipment = None

        for equipment in data:
            i += 1

            # If toggle_row_num is defined, record first the equipment then, when
            # all construction is done, call toggle_article function.
            if toggle_row_num and toggle_row_num == i:
                toggle_equipment = equipment
            if self.chosen and self.chosen == equipment["id"]:
                toggle_equipment = equipment
                toggle_row_num = i
                self.row_widget_num = i

            label = Gtk.Label(equipment["name"], xalign=0)
            label.set_line_wrap(True)
            label.set_lines(1)
            label.set_line_wrap_mode(2)
            label.get_style_context().add_class("item-cell")
            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 0, i, 1, 1)

            label = Gtk.Label(equipment["remark"], xalign=0)
            label.set_line_wrap(True)
            label.set_lines(1)
            label.set_line_wrap_mode(2)
            label.get_style_context().add_class("item-cell")
            label.get_style_context().add_class("article-remark")
            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 1, i, 1, 1)

            label = Gtk.Label(equipment["packaging"], xalign=0)
            label.get_style_context().add_class("item-cell")
            label.set_line_wrap(True)
            label.set_lines(1)
            label.set_line_wrap_mode(2)
            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 2, i, 1, 1)

            # Get list of locations
            locations_len = len(equipment["locations"])
            if locations_len == 0:
                locations_display = ""
            elif locations_len >= 1:
                equipment["locations"].sort()
                locations_display = equipment["locations"][0]
            if locations_len > 1:
                locations_display += ", ..."

            label = Gtk.Label(locations_display, xalign=0)
            label.set_line_wrap(True)
            label.set_lines(1)
            label.set_line_wrap_mode(2)
            label.get_style_context().add_class("item-cell")
            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 3, i, 1, 1)

            # Get first expiry date
            date_display = ""
            if len(equipment["exp_dates"]
                   ) > 0 and None not in equipment["exp_dates"]:
                date_display = min(equipment["exp_dates"]).strftime("%Y-%m-%d")

            label = Gtk.Label(date_display, xalign=0.5)
            label.get_style_context().add_class("item-cell")
            label.get_style_context().add_class("text-mono")
            if equipment["has_date_expired"]:
                label.get_style_context().add_class("article-expired")
            elif equipment["has_date_warning"]:
                label.get_style_context().add_class("article-warning")

            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 4, i, 1, 1)

            label = Gtk.Label(xalign=0.5)
            label.set_markup("{0}<small>/{1}</small>".format(
                equipment["quantity"], equipment["required_quantity"]))
            label.get_style_context().add_class("item-cell")
            label.get_style_context().add_class("text-mono")
            # Change style if equipment has articles with non-conformity
            if equipment["has_nc"]:
                label.get_style_context().add_class("item-nc-quantity")
            # If quantity is less than required, affect corresponding style
            if equipment["quantity"] < equipment["required_quantity"]:
                label.get_style_context().add_class("article-expired")

            evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
            evbox.add(label)
            grid.attach(evbox, 5, i, 1, 1)

            # Set tooltip to give information on allowances requirements
            tooltip_text = []
            for item in equipment["allowance"]:
                tooltip_text.append("<b>{0}</b> ({1})".format(
                    item["name"], item["quantity"]))
            label.set_tooltip_markup("\n".join(tooltip_text))

            if equipment["picture"]:
                # Button box for actions
                linked_btn = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
                linked_btn.get_style_context().add_class("linked")
                linked_btn.get_style_context().add_class(
                    "equipment-item-buttons")
                evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
                evbox.add(linked_btn)
                grid.attach(evbox, 6, i, 1, 1)

                # Picture
                picture = equipment["picture"]
                btn_picture = widgets.ButtonWithImage(
                    "image-x-generic-symbolic",
                    tooltip=_("View picture"),
                    connect=utils.picture_frame,
                    data=picture)
                linked_btn.pack_end(btn_picture, False, True, 0)
            else:
                label = Gtk.Label("", xalign=0.5)
                label.get_style_context().add_class("item-cell")
                evbox = widgets.EventBox(equipment, self.toggle_article, 7, i)
                evbox.add(label)
                grid.attach(evbox, 6, i, 1, 1)

        # Toggle if active
        if toggle_row_num and toggle_equipment:
            self.toggle_article(source=None,
                                grid=grid,
                                equipment=toggle_equipment,
                                row_num=toggle_row_num)

        query_count_all()

        return grid
Ejemplo n.º 30
0
    def toggle_article(self, source, grid, equipment, row_num):
        # If already toggled, destroy the toggled part
        if self.toggled and self.toggled[0] > 0:
            # Remove the active-row CSS class of the parent item
            utils.grid_row_class(grid, self.toggled[0] - 1, 7, False)

            for i in range(self.toggled[1] - self.toggled[0] + 1):
                grid.remove_row(self.toggled[0])
            # No need to recreate the widget, we just want to hide
            if row_num + 1 == self.toggled[0]:
                self.toggled = False
                return True

        # Add the active-row CSS class
        utils.grid_row_class(grid, row_num, 7)

        # Need to create the content
        new_row = row_num + 1
        grid.insert_row(new_row)

        # Header row
        label = Gtk.Label(_("Commercial Name"), xalign=0)
        label.set_hexpand(True)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 0, 0 + new_row, 1, 1)

        label = Gtk.Label(_("Remarks"), xalign=0)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 1, 0 + new_row, 2, 1)

        label = Gtk.Label(_("Location"), xalign=0)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 3, 0 + new_row, 1, 1)

        label = Gtk.Label(_("Expiry"), xalign=0.5)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 4, 0 + new_row, 1, 1)

        label = Gtk.Label(_("Quantity"), xalign=0.5)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 5, 0 + new_row, 1, 1)

        label = Gtk.Label(_("Actions"), xalign=1)
        label.get_style_context().add_class("article-header-cell")
        grid.attach(label, 6, 0 + new_row, 1, 1)

        # Get related articles
        articles = equipment["articles"]

        i = new_row
        for article in articles:
            i += 1
            grid.insert_row(i)

            label = Gtk.Label(article["name"], xalign=0)
            label.set_hexpand(True)
            label.get_style_context().add_class("article-item-cell-name")
            label.get_style_context().add_class("article-item-cell")
            grid.attach(label, 0, i, 1, 1)

            # Remark field (mainly used for non-compliance)
            remark_text = []

            if article["nc_packaging"]:
                remark_text.append(
                    NC_TEXT_TEMPLATE.format(_("Non-compliant packaging:"),
                                            article["nc_packaging"]))
            if article["remark"]:
                remark_text.append(article["remark"])

            label = Gtk.Label(xalign=0)
            label.set_markup("\n".join(remark_text))
            label.get_style_context().add_class("article-item-cell")
            label.get_style_context().add_class("article-remark")

            grid.attach(label, 1, i, 2, 1)

            label = Gtk.Label(xalign=0)
            label.get_style_context().add_class("article-item-cell")
            sequence = article["location"]["sequence"]
            if len(sequence) > 1:
                parents = " > ".join(sequence[:-1])
                location_display = "<span foreground=\"#555\">{0} > </span>{1}".format(
                    parents, sequence[-1])
            else:
                location_display = sequence[0]

            label.set_markup(location_display)
            label.set_line_wrap(True)
            label.set_lines(1)
            label.set_line_wrap_mode(2)
            grid.attach(label, 3, i, 1, 1)

            if article["exp_date"]:
                label = Gtk.Label(article["exp_date"].strftime("%Y-%m-%d"),
                                  xalign=0.5)
                label.get_style_context().add_class("text-mono")
            else:
                label = Gtk.Label()
            label.get_style_context().add_class("article-item-cell")

            # If expiry is soon or due, affect corresponding style
            if article["expired"]:
                label.get_style_context().add_class("article-expired")
            elif article["warning"]:
                label.get_style_context().add_class("article-warning")
            grid.attach(label, 4, i, 1, 1)

            label = Gtk.Label(article["quantity"], xalign=0.5)
            label.get_style_context().add_class("article-item-cell")
            label.get_style_context().add_class("text-mono")
            grid.attach(label, 5, i, 1, 1)

            # Button box for actions
            linked_btn = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            linked_btn.get_style_context().add_class("linked")
            linked_btn.get_style_context().add_class("article-item-buttons")
            # linked_btn.set_halign(Gtk.Align.END)
            grid.attach(linked_btn, 6, i, 1, 1)

            # Use
            if equipment["consumable"]:
                btn_use = widgets.ButtonWithImage("edit-redo-symbolic",
                                                  tooltip=_("Use"),
                                                  connect=self.dialog_use,
                                                  data=article)
                linked_btn.pack_end(btn_use, False, True, 0)
            # Modify
            btn_modify = widgets.ButtonWithImage("document-edit-symbolic",
                                                 tooltip=_("Modify"),
                                                 connect=self.dialog_modify,
                                                 data=article)
            linked_btn.pack_end(btn_modify, False, True, 0)
            # Delete
            btn_delete = widgets.ButtonWithImage("edit-delete-symbolic",
                                                 tooltip=_("Delete"),
                                                 connect=self.dialog_delete,
                                                 data=article)
            btn_delete.get_style_context().add_class("article-btn-delete")
            linked_btn.pack_end(btn_delete, False, True, 0)

        i += 1
        grid.insert_row(i)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button = Gtk.Button()
        label = Gtk.Label(_("Add an article"), xalign=0)
        button.add(label)
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.get_style_context().add_class("article-btn-add")
        button.connect("clicked", self.dialog_add, equipment)
        box.add(button)
        box.get_style_context().add_class("article-item-cell-add")
        grid.attach(box, 0, i, 1, 1)

        # Empty row for styling purpose
        label = Gtk.Label("")
        label.get_style_context().add_class("article-item-cell-add")
        grid.attach(label, 1, i, 6, 1)

        grid.show_all()
        self.toggled = (new_row, i)

        query_count_all()