Extension methods are static with all the cons implied,
Because an extension method is just a static method that takes this
as its first parameter and doesn't expose the inner workings of this
, it encourages the developer down the "pit of success" of pure functions. The major "con" with static methods is when they access, or worse modify, global state. This isn't (or at least shouldn't be, if done correctly) the case with extension methods.
So the only real "con" with a well written extension method is that they upset "OO purists".
and I believe the 'most-correct' OO way to handle this kind of refactor would be to wrap it in a 'Orders' object and expose property(ies) that do this instead.
That's often the problem with trying to take a purist approach. It may well be "correct" from a "pure OO" standpoint, but you've now added the complexity of a wrapper class and needing to create instances of it, rather than dealing with your eg List<Order>
that you previously had. And the only reason that complexity has been added is to make it appear more "correct".
As a rule of thumb, for your own classes, use methods to do something to a object (access or change its internal state) and extension methods to do something with an object (typically transform it as per your example). Extension methods shouldn't just be seen as a means of extending others' classes, they are also a neat way of extending your own classes without cluttering the main class file with ancillary functionality.
As a second rule of thumb, If I have need of a function that fits the "pure" requirements (processes, but doesn't modify) its parameters to derive a new value without side effects), then I'd make it a static. It simplifies the code over having to create instance of a new class. If it makes sense, syntactically, to use it as an extension method, then make it that too.
C# isn't an OO language; it's a multi-paradigm language with OO features. So don't worry about the extreme views of "OO purists" when deciding on the best approach for your requirements.
IEnumerable<int> GetShippedOrderIds()
which can be accessible to other Services and Controllers, as well as mockable for unit tests.