I agree with hippo
's suggestion that 'Checkout' should be part of the name. Also
- Your class is doing checkout handling and trolley handling (Single responsibility pattern / Cohesion). Consider having a separate Trolley object for trolley handling.
- The pattern of iterating over the trolley and doing something to just one item suggests the trolley ought to be a hash (keyed by the product ID). You can add extra keys to aid with sorting if you need that.
- Consider using Moo or something similar to make the OOP more ergonomic.
- Exceptions are usually preferable to silent returns because they are harder to ignore (see Try::Tiny).
- 'unless' is tricky for many people (it doesn't scale up, can lead to double negatives etc).
- 'and' and '&&' are not the same thing (the former is for combining statements)