def _process_row(self, row: Dict[str, Any], filename: str = None, line_num: int = None) -> Dict[str, Any]: raw_size = row["Quantity"] try: row["Quantity"], row["Unit"] = Unit.from_exp(raw_size) except RuntimeError as e: raise UserFacingException(str(e)) row["Formula#"] = self.formulas[row["Name"]] ingr = Ingredient.objects.filter(number=row["Ingr#"]) if not ingr.exists(): raise IntegrityException( message="Cannot import Formula", line_num=line_num, referring_name="Formula", referred_name="Ingredient", fk_name="Ingr#", fk_value=row["Ingr#"], ) ingr = ingr[0] if row["Unit"].unit_type != ingr.unit.unit_type: raise UserFacingException( f"Cannot import Formula.\nUnit '{row['Unit'].symbol}' is incompatible " f"with unit '{ingr.unit.symbol}' used in ingredient '{ingr.name}'." ) row["Ingr#"] = ingr return row
def _process_row(self, row: Dict[str, Any], filename: str = None, line_num: int = None) -> Dict[str, Any]: raw_size = row["Size"] try: row["Size"], row["Unit"] = Unit.from_exp(raw_size) except RuntimeError as e: raise UserFacingException(str(e)) try: # The CSV parser is being too "helpful" by converting size to a float... row["Size"] = Decimal(str(row["Size"])) except InvalidOperation: raise UserFacingException( f"{row['Size']}is not a valid decimal number") try: row["Cost"] = Decimal(utils.parse_usd(row["Cost"])) except ValueError as e: raise UserFacingException(str(e)) vendor = Vendor.objects.filter(info=row["Vendor Info"]) if vendor.exists(): row["Vendor Info"] = vendor[0] else: row["Vendor Info"] = Vendor.objects.create(info=row["Vendor Info"]) if row["Comment"] is None: row["Comment"] = "" return row
def auto_schedule(request): if not request.user.is_plant_manager: raise UserFacingException("You are not authorized to use the auto-scheduler.") items = json.loads(request.POST.get("items", "[]")) existing = json.loads(request.POST.get("existing", "{}")) start = request.POST.get("start", "") end = request.POST.get("end", "") scheduler_name = request.POST.get("scheduler", "") current_timezone = timezone.get_current_timezone() try: start = datetime.fromtimestamp(int(start), tz=current_timezone) end = datetime.fromtimestamp(int(end), tz=current_timezone) except ValueError: raise UserFacingException("Unable to schedule: invalid start/end time") if start >= end: raise UserFacingException( "Unable to schedule: end time is less than start time" ) if not items: # Return empty schedule return "[]" to_schedule = [] existing_items = {} try: owned_lines = request.user.owned_lines for item in items: to_schedule.append( scheduling.Item( GoalItem.objects.get(id=item["id"]), int(item["hours"]), set(item["groups"]).intersection(owned_lines), ) ) for group, items in existing.items(): if not group in owned_lines: continue existing_items[group] = [ scheduling.ExistingItem( GoalItem.objects.get(id=item["id"]), datetime.fromtimestamp(int(item["start"]), tz=current_timezone), datetime.fromtimestamp(int(item["end"]), tz=current_timezone), ) for item in items ] except Exception: logger.exception("Invalid auto-schedule request") raise UserFacingException("Unable to schedule: invalid request.") try: scheduler = scheduling.get_scheduler(scheduler_name) result = scheduler(to_schedule, existing_items, start, end) except scheduling.ScheduleException as e: raise UserFacingException(str(e)) return json.dumps(result)
def _to_decimal(row: Dict[str, Any], fields: Iterable[str]) -> None: for field in fields: try: row[field] = Decimal(str(row[field])) except InvalidOperation: raise UserFacingException( f"'{row[field]}' is not a valid floating point number.")
def commit(self) -> Tuple[int, int, int]: """ Force commits all instances, including collisions. :return: a 3-tuple (inserted, updated, ignored) of integers representing the numbers of instances in each category. """ if not self.is_bound: raise UserFacingException( "Data corruption detected. Please try importing " "again. Error code: ENOTBOUND") for instance in self._instances: self.__save(instance.instance) self._save_m2m(instance) for record in self._collisions: ex = record.instance ex.old_instance.delete() self.__save(ex.new_instance) self._save_m2m(record) for record in self._ignored: # Even though the instance itself is ignored, it doesn't mean that # its M2M fields haven't changed. We save those here. self._save_m2m(record) self._post_process() return len(self.instances), len(self.collisions), len(self.ignored)
def _parse_usd(row: Dict[str, Any], fields: Iterable[str]): for field in fields: try: row[field] = Decimal(utils.parse_usd(row[field])) except (InvalidOperation, ValueError): raise UserFacingException( "Cost must be a USD expression; " f"'{row[field]}' is not a valid USD expression.")
def remove_lines(request): try: line_ids = set(map(int, json.loads(request.GET.get("toRemove", "[]")))) except ValueError as e: raise UserFacingException(f"Invalid Manufacturing Line IDs: '{e:s}'") _, deleted = ManufacturingLine.objects.filter(pk__in=line_ids).delete() return ( f"Successfully deleted {deleted.get('meals.ManufacturingLine', 0)} " "Manufacturing Line(s)")
def _find_users_by_id(user_ids): user_objs = User.objects.filter(pk__in=user_ids) found = set(user_objs.values_list("pk", flat=True)) missing = user_ids - found if missing: raise UserFacingException( f"The following user IDs cannot be found: {', '.join(map(str, missing))}" ) return user_objs
def view_pl_skus(request, pk): queryset = ProductLine.objects.filter(pk=pk) if queryset.exists(): pl = queryset[0] skus = pl.sku_set.all() resp = render_to_string( template_name="meals/sku/view_sku.html", context={"pl_skus": skus}, request=request, ) return resp raise UserFacingException(f"Product Line with ID '{pk}' not found.")
def sales_projection(request): sku_number = request.GET.get("sku", None) if not sku_number: raise UserFacingException("Invalid request: no SKU was provided") start_date = request.GET.get("start", None) or datetime.now() - timedelta(days=10) end_date = request.GET.get("end", None) or datetime.now() sku_qs = Sku.objects.filter(number=sku_number) if sku_qs.exists(): sku = sku_qs[0] else: raise UserFacingException( f"Invalid request: SKU #{sku_number} cannot be found.") params = {"start": start_date, "end": end_date} form = ProjectionsFilterForm(params) if form.is_valid(): data = form.query(sku_number) else: data = {} if data: avg = statistics.mean(data.values()) std = statistics.stdev(data.values()) else: avg = std = Decimal("0.0") form_html = render_to_string( request=request, template_name="meals/sales/projection.html", context={ "data": data, "form": form, "sku": sku, "avg": avg, "std": std }, ) return form_html
def remove_users(request): user_ids = set(map(int, json.loads(request.GET.get("u", "[]")))) if not user_ids: return "No user was selected." user_objs = _find_users_by_id(user_ids) superusers = user_objs.filter(is_superuser=True) if superusers.exists(): raise UserFacingException( f"User '{superusers[0].username}' is reserved and cannot be removed." ) _, deleted = user_objs.delete() logger.info("Deleted=%s", deleted) num_deleted = deleted.get("meals.User", 1) return f"Successfully deleted {num_deleted} user(s)."
def _check_duplicates( self, raw: Dict[str, str], converted: Dict[str, Any], filename: str, line_num: int, ): name_value = (raw["Name"], ) if name_value in self.unique_dict[("name", )]: prev_line_num = self.unique_dict[("name", )][name_value] if raw["Formula#"]: formula_number = (raw["Formula#"], ) unique_dict = self.unique_dict[("number", )] if (formula_number not in unique_dict or unique_dict[formula_number] != prev_line_num): raise UserFacingException( f"Cannot import Formula: formula name '{name_value[0]}' " "and number mismatched. Expected number to match with record " f"in line {prev_line_num}.") else: raise Skip else: raise Skip super()._check_duplicates(raw, converted, filename, line_num)
def _process_row(self, row: Dict[str, Any], filename: str = None, line_num: int = None) -> Dict[str, Any]: try: row["SKU#"] = int(row["SKU#"]) except ValueError: raise UserFacingException( f"SKU number must be numeric; '{row['SKU#']}' is not a valid integer." ) row["Count per case"] = int(row["Count per case"]) raw_formula = row["Formula#"] formula_qs = Formula.objects.filter(number=raw_formula) if formula_qs.exists(): row["Formula#"] = formula_qs[0] else: raise IntegrityException( message=f"Cannot import SKU #{row['SKU#']}", line_num=line_num, referring_name="SKU", referred_name="Formula", fk_name="Formula", fk_value=row["Formula#"], ) for field in ["Case UPC", "Unit UPC"]: if utils.is_valid_upc(row[field]): if str(row[field])[0] not in ["2", "3", "4", "5"]: row[field] = Upc.objects.get_or_create( upc_number=row[field])[0] else: raise ValidationError( "%(field)s must be a valid consumer UPC; '%(upc)s' is not a " "valid consumer UPC number.", params={ "field": field, "upc": row[field] }, ) else: raise UserFacingException(f"{row[field]} is not a valid UPC.") if row["Comment"] is None: row["Comment"] = "" product_line = ProductLine.objects.filter(name=row["PL Name"]) if product_line.exists(): row["PL Name"] = product_line[0] else: raise IntegrityException( message=f"Cannot import SKU #{row['SKU#']}", line_num=line_num, referring_name="SKU", referred_name="Product Line", fk_name="PL Name", fk_value=row["PL Name"], ) row["ML Shortnames"] = self._check_manufacturing_line(row, line_num) self._to_decimal(row, ["Rate", "Formula factor"]) self._parse_usd(row, ["Mfg setup cost", "Mfg run cost"]) return row