|
| 1 | +package dev.atedeg.mdm.pricing |
| 2 | + |
| 3 | +import java.util.UUID |
| 4 | +import java.time.LocalDateTime |
| 5 | + |
| 6 | +import dev.atedeg.mdm.products.Product |
| 7 | +import dev.atedeg.mdm.utils.* |
| 8 | +import dev.atedeg.mdm.utils.given |
| 9 | +import cats.data.NonEmptyList |
| 10 | + |
| 11 | +/** |
| 12 | + * A [[Product product]] with its ordered [[Quantity quantity]]. |
| 13 | + */ |
| 14 | +final case class IncomingOrderLine(quantity: Quantity, product: Product) |
| 15 | + |
| 16 | +/** |
| 17 | + * A quantity of something. |
| 18 | + */ |
| 19 | +final case class Quantity(n: PositiveNumber) |
| 20 | + |
| 21 | +/** |
| 22 | + * Associates to each [[Product product]] its [[PriceInEuroCents unitary price]]. |
| 23 | + */ |
| 24 | +final case class PriceList(priceList: Map[Product, PriceInEuroCents]) |
| 25 | + |
| 26 | +/** |
| 27 | + * A price expressed in cents, the smallest currency unit for euros. |
| 28 | + */ |
| 29 | +final case class PriceInEuroCents(n: PositiveNumber) derives Plus |
| 30 | + |
| 31 | +/** |
| 32 | + * A physical or legal entity that places [[IncomingOrderLine order lines]]. |
| 33 | + */ |
| 34 | +final case class Client(code: ClientID) |
| 35 | + |
| 36 | +/** |
| 37 | + * An ID which uniquely identifies a [[Client client]]. |
| 38 | + */ |
| 39 | +final case class ClientID(id: UUID) |
| 40 | + |
| 41 | +/** |
| 42 | + * A list of all the promotions for each [[Client client]]. |
| 43 | + */ |
| 44 | +final case class PromotionsList(promotions: Map[Client, NonEmptyList[Promotion]]) |
| 45 | + |
| 46 | +/** |
| 47 | + * A promotion for a [[Client client]], with an expiry date. |
| 48 | + * It can either be fixed or by threshold. |
| 49 | + * If it is fixed, a product is discounted by a fixed amount; |
| 50 | + * if it is by threshold, only the products above the threshold are discounted. |
| 51 | + */ |
| 52 | +enum Promotion: |
| 53 | + /** |
| 54 | + * A fixed promotion. |
| 55 | + */ |
| 56 | + case Fixed(client: Client, expiryDate: LocalDateTime, lines: NonEmptyList[PromotionLine.Fixed]) |
| 57 | + /** |
| 58 | + * A threshold promotion. |
| 59 | + */ |
| 60 | + case Threshold(client: Client, expiryDate: LocalDateTime, lines: NonEmptyList[PromotionLine.Threshold]) |
| 61 | + |
| 62 | +/** |
| 63 | + * A promotion line, which describes either the |
| 64 | + * [[Promotion.Fixed fixed]] or the [[Promotion.Threshold threshold]] promotion. |
| 65 | + */ |
| 66 | +enum PromotionLine: |
| 67 | + /** |
| 68 | + * A line that describes part of a [[Promotion.Fixed fixed promotion]]. |
| 69 | + * It contains the discounted product and how much to discount it by. |
| 70 | + * |
| 71 | + * Every order line which contains the product is discounted by the specified amount. |
| 72 | + * |
| 73 | + * @note For example, if a 100g casatella normally costs 100 cents and the promotion line specifies |
| 74 | + * a 50% discount, each 100g casatella will cost 50 cents. |
| 75 | + */ |
| 76 | + case Fixed(product: Product, discount: DiscountPercentage) |
| 77 | + /** |
| 78 | + * A line that describes part of a [[Promotion.Threshold threshold promotion]]. |
| 79 | + * It contains the discounted product, the threshold and how much to discount it by. |
| 80 | + * |
| 81 | + * Only the products above the threshold are discounted; the other ones are at full price. |
| 82 | + * |
| 83 | + * @note For example, if a 100g casatella normally costs 100 cents and the promotion line specifies |
| 84 | + * a 50% discount above 5 casatellas, the first 5 casatella will cost 100 cents, while from the 6th onwards |
| 85 | + * they will cost 50 cents each. |
| 86 | + */ |
| 87 | + case Threshold(product: Product, threshold: Quantity, discount: DiscountPercentage) |
| 88 | + |
| 89 | +/** |
| 90 | + * A discount percentage, expressed as a number between 0 (exclusive) and 100 (inclusive). |
| 91 | + */ |
| 92 | +final case class DiscountPercentage(n: DecimalInOpenClosedRange[0, 100]) |
0 commit comments