Generating a Report
Part of the Logic & Flow section of Coddy's GO journey — lesson 49 of 68.
Challenge
EasyComplete your inventory management system by implementing a comprehensive reporting function that provides detailed insights into your current inventory. This challenge builds on all previous functionality and adds the ability to generate formatted reports with statistics, categorization, and analysis.
You will receive two inputs:
- A string containing existing inventory data in the format
"product1:price1:quantity1,product2:price2:quantity2,product3:price3:quantity3"(e.g.,"Laptop:999.99:5,Mouse:25.50:15,Keyboard:75.00:8") - A string containing report configuration in the format
"report_type,threshold_value"where report_type can be"full","low_stock", or"high_value"and threshold_value is a number (e.g.,"low_stock,10")
Your task is to:
- Use the same
Productstruct from previous lessons withPrice(float64) andQuantity(int) fields - Parse the first input by splitting on commas to get individual existing product entries
- For each existing product entry, split on colons to get product name, price, and quantity
- Convert the price string to float64 and quantity string to int
- Create and populate the
inventorymap with the existing product data - Create a function called
generateReportthat takes the inventory map, report type, and threshold value as parameters - Parse the second input by splitting on commas to get report type and threshold value
- Convert the threshold value string to float64
- Display the report header based on the report type:
- For
"full":"=== FULL INVENTORY REPORT ===" - For
"low_stock":"=== LOW STOCK REPORT ===" - For
"high_value":"=== HIGH VALUE REPORT ==="
- For
- Display general inventory statistics:
"Total Products: [total_number_of_products]""Total Items in Stock: [sum_of_all_quantities]""Total Inventory Value: $[sum_of_price_times_quantity_for_all_products]""Average Product Price: $[total_inventory_value_divided_by_total_items]"
- Filter and display products based on report type:
- For
"full": Show all products - For
"low_stock": Show only products with quantity less than or equal to threshold value - For
"high_value": Show only products with total value (price × quantity) greater than or equal to threshold value
- For
- Display the filtered products section:
- For
"full":"All Products:" - For
"low_stock":"Products with stock ≤ [threshold_value]:" - For
"high_value":"Products with value ≥ $[threshold_value]:"
- For
- For each filtered product (in alphabetical order by product name):
"- [product_name]: $[price] × [quantity] = $[total_value]"
- Display filtered statistics:
"Filtered Results:""Products shown: [number_of_products_in_filtered_results]""Items in filtered products: [sum_of_quantities_for_filtered_products]""Value of filtered products: $[sum_of_values_for_filtered_products]"
- Find and display the most expensive and least expensive products:
"Price Analysis:""Most expensive: [product_name] at $[price]""Least expensive: [product_name] at $[price]"
- Find and display the highest and lowest stock products:
"Stock Analysis:""Highest stock: [product_name] with [quantity] units""Lowest stock: [product_name] with [quantity] units"
- Display inventory health assessment:
- Count products with quantity ≤ 5:
"Low stock items (≤5): [count]" - Count products with quantity > 20:
"High stock items (>20): [count]" - Count products with value ≥ $500:
"High value items (≥$500): [count]"
- Count products with quantity ≤ 5:
- Display report completion:
"Report generated successfully""Threshold applied: [threshold_value]"
Use the strings package to split the input strings, the strconv package to convert strings to numbers, the fmt package for formatted output, and the sort package to sort product names alphabetically. Format all prices and values to 2 decimal places. When finding most/least expensive or highest/lowest stock, if there are ties, use the alphabetically first product name. This challenge demonstrates how to create comprehensive reporting systems that provide valuable business insights through data analysis and formatted presentation.
Try it yourself
package main
import (
"errors"
"fmt"
"sort"
"strconv"
"strings"
)
type Product struct {
Price float64
Quantity int
}
func updateStock(inventory map[string]Product, productName string, change int) error {
product, exists := inventory[productName]
if !exists {
return errors.New("product not found: " + productName)
}
newQuantity := product.Quantity + change
if newQuantity < 0 {
return fmt.Errorf("insufficient stock: cannot reduce %s by %d, only %d available", productName, -change, product.Quantity)
}
product.Quantity = newQuantity
inventory[productName] = product
return nil
}
func main() {
var inventoryData string
var updateRequests string
fmt.Scanln(&inventoryData)
fmt.Scanln(&updateRequests)
// Parse existing inventory
inventory := make(map[string]Product)
inventoryEntries := strings.Split(inventoryData, ",")
for _, entry := range inventoryEntries {
parts := strings.Split(entry, ":")
name := parts[0]
price, _ := strconv.ParseFloat(parts[1], 64)
quantity, _ := strconv.Atoi(parts[2])
inventory[name] = Product{
Price: price,
Quantity: quantity,
}
}
// Parse update requests
updateEntries := strings.Split(updateRequests, ",")
fmt.Println("Processing Stock Updates:")
totalUpdates := len(updateEntries)
successfulUpdates := 0
failedUpdates := 0
var failedProducts []string
for _, update := range updateEntries {
parts := strings.Split(update, ":")
productName := parts[0]
change, _ := strconv.Atoi(parts[1])
err := updateStock(inventory, productName, change)
if err != nil {
fmt.Printf("%s: Update failed - %s\n", productName, err.Error())
failedUpdates++
failedProducts = append(failedProducts, productName)
} else {
newQuantity := inventory[productName].Quantity
if change > 0 {
fmt.Printf("%s: Added %d units - New stock: %d\n", productName, change, newQuantity)
} else if change < 0 {
fmt.Printf("%s: Removed %d units - New stock: %d\n", productName, -change, newQuantity)
} else {
fmt.Printf("%s: No change - Current stock: %d\n", productName, newQuantity)
}
successfulUpdates++
}
}
// Update summary
fmt.Println("Update Summary:")
fmt.Printf("Updates processed: %d\n", totalUpdates)
fmt.Printf("Updates successful: %d\n", successfulUpdates)
fmt.Printf("Updates failed: %d\n", failedUpdates)
// Display updated inventory in alphabetical order
fmt.Println("Updated Inventory:")
var productNames []string
for name := range inventory {
productNames = append(productNames, name)
}
sort.Strings(productNames)
for _, name := range productNames {
product := inventory[name]
fmt.Printf("- %s: $%.2f (Stock: %d)\n", name, product.Price, product.Quantity)
}
// Calculate final statistics
totalProducts := len(inventory)
totalItems := 0
totalValue := 0.0
for _, product := range inventory {
totalItems += product.Quantity
totalValue += product.Price * float64(product.Quantity)
}
fmt.Println("Final Inventory Statistics:")
fmt.Printf("Total Products: %d\n", totalProducts)
fmt.Printf("Total Items in Stock: %d\n", totalItems)
fmt.Printf("Total Inventory Value: $%.2f\n", totalValue)
// List failed updates
if len(failedProducts) > 0 {
fmt.Printf("Failed updates: %s\n", strings.Join(failedProducts, ","))
} else {
fmt.Println("All stock updates were processed successfully")
}
}All lessons in Logic & Flow
1Advanced Control Flow
Switch with `fallthrough`Breaking from Nested LoopsContinuing a Specific LoopThe `goto` StatementRecap - Advanced Loop Control4Project: Simple Task List
Project SetupAdding a Task2Structs and Methods
Defining Methods on StructsValue ReceiversPointer ReceiversChoosing ReceiversMethods vs FunctionsRecap - Struct Behavior5Maps In-Depth
Maps of StructsPointers as Map ValuesTesting for Nil MapsComparing MapsRecap - Word Frequency Counter8Project: Simple Inventory
Project OverviewChecking Stock3Interfaces (The Basics)
What is an Interface?Defining an InterfaceImplementing an InterfaceUsing Interface TypesEmpty InterfaceType AssertionsType SwitchRecap - Shapes and Behaviors