Skip to content

Instantly share code, notes, and snippets.

@ntngel1
Created April 11, 2024 18:45
Show Gist options
  • Save ntngel1/7c56a2f3b64350cc9a0b1cb824d9bf32 to your computer and use it in GitHub Desktop.
Save ntngel1/7c56a2f3b64350cc9a0b1cb824d9bf32 to your computer and use it in GitHub Desktop.
sealed trait AcquiringOrder extends Product with Serializable {
val id: BSONObjectID
val info: AcquiringOrder.Info
val createdAt: OffsetDateTime
val updatedAt: OffsetDateTime
}
object AcquiringOrder {
case class Info(
acquiring: AcquiringType,
acquiringOrderId: String,
amount: MoneyAmount,
currency: CurrencyUnit,
paymentUrl: String
)
sealed trait HasRefunds extends AcquiringOrder {
val refunds: Seq[AcquiringRefund]
}
sealed trait HasPayment extends AcquiringOrder {
val payment: AcquiringPayment
}
sealed trait Paidable extends AcquiringOrder {
val maybePaymentId: Option[String]
def paid(payment: AcquiringPayment): Paid
}
sealed trait Refundable extends AcquiringOrder with HasPayment {
def refunded(refund: AcquiringRefund): HasRefunds
def refunded(refunds: Seq[AcquiringRefund]): HasRefunds
}
case class WaitingForPayment(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
maybePaymentId: Option[String]
) extends AcquiringOrder with Paidable {
override def paid(
payment: AcquiringPayment
): Paid = Paid(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = Seq.empty
)
}
object WaitingForPayment {
def apply(
order: AcquiringOrder,
paymentId: Option[String]
): WaitingForPayment = new WaitingForPayment(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
maybePaymentId = paymentId
)
}
case class WaitingForCapture(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund.InProgressOrRejected]
) extends AcquiringOrder with Refundable with Paidable with HasRefunds {
override val maybePaymentId: Option[String] = payment.id.some
override def paid(
payment: AcquiringPayment = this.payment
): Paid = Paid(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = Seq.empty
)
override def refunded(
refunds: Seq[AcquiringRefund]
): HasRefunds = refunds match {
case refunds: Seq[AcquiringRefund.InProgressOrRejected] =>
refunded(refunds)
case refunds =>
refunds
.collectFirst { case refund: AcquiringRefund.Succeeded => refund }
.map { case refund if refund.amount == payment.amount =>
Canceled(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment.some,
refunds = refunds
)
}
.getOrElse(
Refunded(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
)
}
override def refunded(
refund: AcquiringRefund
): HasRefunds = refunded(refunds.appended(refund))
def refunded(
refunds: Seq[AcquiringRefund.InProgressOrRejected]
): WaitingForCapture = copy(refunds = refunds)
def refunded(
refund: AcquiringRefund.InProgressOrRejected
): WaitingForCapture = refunded(refunds = refunds.appended(refund))
def refunded(
refund: AcquiringRefund.Succeeded
): HasRefunds = refunded(refunds.appended(refund))
}
object WaitingForCapture {
def apply(
order: AcquiringOrder,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund.InProgressOrRejected]
): WaitingForCapture = new WaitingForCapture(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
}
case class Paid(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund.InProgressOrRejected]
) extends AcquiringOrder with Refundable with HasRefunds {
override def refunded(
refunds: Seq[AcquiringRefund]
): HasRefunds = refunds match {
case refunds: Seq[AcquiringRefund.InProgressOrRejected] => refunded(refunds)
case refunds => Refunded(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
}
override def refunded(
refund: AcquiringRefund
): HasRefunds = refunded(refunds.appended(refund))
def refunded(
refunds: Seq[AcquiringRefund.InProgressOrRejected]
): Paid = copy(refunds = refunds)
def refunded(
refund: AcquiringRefund.InProgressOrRejected
): Paid = refunded(refunds = refunds.appended(refund))
def refunded(
refund: AcquiringRefund.Succeeded
): Refunded = Refunded(
id = id,
info = info,
createdAt = createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds.appended(refund)
)
}
object Paid {
def apply(
order: AcquiringOrder,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund.InProgressOrRejected]
): Paid = new Paid(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
}
case class Refunded(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund]
) extends AcquiringOrder with Refundable with HasRefunds {
override def refunded(
refunds: Seq[AcquiringRefund]
): Refunded = copy(refunds = refunds)
override def refunded(
refund: AcquiringRefund
): Refunded = copy(refunds = refunds.appended(refund))
def refundsAmount: MoneyAmount = refunds.filter(_.isSucceeded).sumBy(_.amount)
}
object Refunded {
def apply(
order: AcquiringOrder,
payment: AcquiringPayment,
refunds: Seq[AcquiringRefund]
): Refunded = new Refunded(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
}
case class Canceled(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
payment: Option[AcquiringPayment],
refunds: Seq[AcquiringRefund]
) extends AcquiringOrder with HasRefunds
object Canceled {
def apply(
order: AcquiringOrder,
payment: Option[AcquiringPayment],
refunds: Seq[AcquiringRefund]
): Canceled = new Canceled(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
payment = payment,
refunds = refunds
)
}
case class Rejected(
id: BSONObjectID,
info: AcquiringOrder.Info,
createdAt: OffsetDateTime,
updatedAt: OffsetDateTime,
paymentId: Option[String],
reason: Option[String]
) extends AcquiringOrder
object Rejected {
def apply(
order: AcquiringOrder,
paymentId: Option[String],
reason: Option[String]
): Rejected = new Rejected(
id = order.id,
info = order.info,
createdAt = order.createdAt,
updatedAt = OffsetDateTime.now(),
paymentId = paymentId,
reason = reason
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment