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
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")
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"]))
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])
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 []
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)
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
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
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
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