Bugnik
← All problems

46Order Update Digest

C++EasyBug fixSuggested time: 60 min

Order update digest builder (daily customer digests, mute preferences, carrier retries, line cap)

New to repository-based OA questions? Read the guide.

Open in IDE

Before you start

You'll get more out of this problem if you're comfortable with:

Language

  • C++17 structs, enum class and namespaces
  • std::string, std::vector, std::map and std::set

Libraries and frameworks

  • The C++ standard library: <algorithm> sorting

Build and test tools

  • Reading test failures with expected and actual values

Reasoning

  • Parsing line-based text formats
  • Turning an event feed into customer messages

Background

The Customer Messaging team at a large online retailer sends each customer one evening message that sums up the day's updates on their orders, instead of a notification for every scan. A small C++ library turns the day's order event feed and the customers' message preferences into those digests. Since the last release, customers have been complaining about what the evening message says.

How the system works

Event feed

One event per line: timestamp | customer | order | kind | detail.

  • Fields are separated by | and trimmed. The detail field is optional, so a line has 4 or 5 fields; anything else is an error.
  • timestamp is YYYY-MM-DDTHH:MM (e.g. 2026-09-14T08:15): month 01–12, day 01–31, hour 00–23, minute 00–59.
  • customer and order must not be empty.
  • kind is one of PLACED, SHIPPED, DELAYED, DELIVERED, CANCELLED, REFUNDED, in any case. Customers see it as Placed, Shipped, Delayed, Delivered, Cancelled, Refunded.
  • Blank lines and lines starting with # are skipped.
  • A malformed line throws ParseError with a message starting line N: (N counts every line from 1).

Urgent updates

An update needs the customer's attention when it is a delay (DELAYED), a cancellation (CANCELLED), or its detail contains the words action needed anywhere, in any case (Action needed: collect from the depot and refund held - ACTION NEEDED both count).

Preferences

One customer per line: customer: settings, where settings are separated by ; and trimmed (empty settings are ignored, so C-305: is valid and changes nothing).

  • mute=<kinds>: a comma-separated list of kinds (any case; empty items ignored) the customer doesn't want. Cancellations are always sent, even when muted.
  • urgent-only: the customer only wants urgent updates.
  • Settings are read in any case. Both settings may be combined; an update must pass both.
  • Blank lines and lines starting with # are skipped. A line without :, an empty customer id, an unknown setting or kind, or a customer listed twice throws ParseError.
  • Customers without a line get every update.

Building digests

buildDigests(events, preferences, day) builds the digests for one day (YYYY-MM-DD):

  1. Only events whose timestamp falls on day are used.
  2. Carrier retries: when the same order has the same kind more than once that day, only the latest one (by timestamp) is kept. On equal timestamps, the one later in the feed wins.
  3. Updates the customer doesn't want (see Preferences) are left out. A customer with no updates left gets no digest at all.
  4. A digest's lines are ordered by timestamp, then order id (A to Z), then kind in the order listed above (PLACED first, REFUNDED last).
  5. urgent is true when any of the customer's remaining updates is urgent.
  6. A digest shows at most 8 lines: when there are more, only the 8 newest are kept and earlierNotShown says how many older ones were left out (they still count for urgent).
  7. Digests are returned in customer id order (A to Z).

Message text

renderDigest joins these lines with \n (no trailing newline):

  1. Order updates for <customer> on <day>
  2. Some of these updates need your attention. (only when urgent)
  3. 1 earlier update not shown / N earlier updates not shown (only when earlierNotShown > 0)
  4. One line per update (renderLine): HH:MM <order> <Kind>, plus - <detail> when the detail isn't empty, e.g. 08:15 ORD-5521 Shipped - via parcel locker. The parts are separated by two spaces.

Project structure

include/ and src/
  util.h / util.cpp                 trim, split, case helpers, timestamp check, ParseError
  event.h / event.cpp               the event feed, kinds and urgent updates
  preferences.h / preferences.cpp   the preferences file and who wants which update
  digest.h / digest.cpp             building the day's digests
  render.h / render.cpp             the message text
tests/
  fixtures.h                        shared test data
  test_util.cpp                     helpers
  test_event.cpp                    feed parsing and urgency
  test_preferences.cpp              preferences
  test_digest.cpp                   building digests
  test_render.cpp                   message text
  testlib.h, runner.cpp             the test framework

Your task

Customers report these problems with the evening message:

  • Almost every message now opens by saying something needs their attention.
  • Some messages show out-of-date delivery information.
  • Some customers say the evening message arrives even on days it has nothing to tell them.

Find and fix the defects so that all tests pass.

  • Do not modify tests/.
  • Keep your changes minimal. Fix the defects; don't rewrite modules.
  • Additional hidden tests check the behaviour described in this README.