in membership-common/src/main/scala/com/gu/memsub/BillingSchedule.scala [73:94]
def sortOutCredits(z: Zipper[Bill]): NonEmptyList[Bill] = z match {
// the end of the list
case Zipper(l, normal, Empty) =>
(l.toList :+ normal).toNel.toOption.get
// we have a negative bill, so we want to zero it and credit the next bill
case Zipper(l, bill, r #:: rs) if bill.totalGross > 0 && bill.amount < 0 =>
val creditAmount = bill.totalDeductions - bill.totalGross
val debitAmount = bill.totalGross - bill.totalDeductions
val cbCredit = BillItem("Credit balance", creditAmount, creditAmount)
val cbDebit = BillItem(s"Credit from ${bill.date}", debitAmount, debitAmount)
sortOutCredits(Zipper(l.append(Stream(bill.addItem(cbCredit))), r.addItem(cbDebit), rs))
// we have a credit note which we want to remove and assign to the next bill
case Zipper(l, credit, r #:: rs) if credit.totalGross == 0 && credit.amount < 0 =>
sortOutCredits(Zipper(l, r.copy(items = r.items.append(credit.items)), rs))
// we have a normal invoice
case Zipper(l, f, r #:: rs) =>
sortOutCredits(Zipper(l :+ f, r, rs))
}