Skip to content

Conversation

@reshmabidikar
Copy link
Contributor

@reshmabidikar reshmabidikar commented Jan 4, 2024

Changes for fixed proration:

  1. Introduced a new property: org.killbill.invoice.proration.fixed.days
  2. Added new tests: TestInvoiceDateUtilsWithFixedProration and TestInvoiceDateUtilsWithoutFixedProration
  3. Tests run fine. I also did a round of manual testing via Kaui and that works fine too.

Need your input on the following:
The Item class also invokes the InvoiceDateUtils.calculateProrationBetweenDates here. Since this class does not have access to InvoiceConfig, I have passed the value 0 corresponding to fixedDaysInMonth. See this comment. I did not spend much time investigating what this class does and whether it requires reading the config parameter but if you think this is important, I'll look into it. Let me know.

@reshmabidikar reshmabidikar marked this pull request as ready for review January 4, 2024 10:25
Copy link
Member

@sbrossie sbrossie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but I based on your TODO, I think we need to double check about the Item class.

final Item[] result = new Item[2];

final BigDecimal amount0 = InvoiceDateUtils.calculateProrationBetweenDates(startDate, splitDate, Days.daysBetween(startDate, endDate).getDays()).multiply(amount);
final BigDecimal amount0 = InvoiceDateUtils.calculateProrationBetweenDates(startDate, splitDate, Days.daysBetween(startDate, endDate).getDays(), 0).multiply(amount); //TODO_fixed_proration - setting to 0, revisit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will need to implement it here as well. I would suggest to write 2 beatrix tests:

  1. One that mimic the current problem being reported, i.e a use case of leading pro-ration (I think you already had it); it should work
  2. One that implements a use case of trailing pro-ration (i.e cancelation before the EOT); I suspect this is where it may break until we fix Item.

Copy link
Member

@sbrossie sbrossie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I just have a few comments around code organization and specifically passing or not the InvoiceConfig. Take a look and let me know what you think.

import org.killbill.billing.util.currency.KillBillMoney;
import org.killbill.commons.utils.annotation.VisibleForTesting;

public class InvoiceDateUtils {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class currently only offers static method, because there is no state that is kept. However, now that we need the config (or at least one param of the config), this makes less sense. It would be better to have a real instance - perhaps injected with guice, that takes a CTOR with the InvoiceConfig, in such a way that we don't mix request parameters (startDate, ...) and static state from the system (config).

  1. Could you experiment to see if this is not too much trouble doing this - I think the result would be much cleaner
  2. If this proves difficult, then at least let's not pass the InvoiceConfig, but instead just the Integer for the prorationFixedDays

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I've updated the methods in InvoiceDateUtils to accept prorationFixedDays instead of invoiceConfig.

return daysBetween;
}
final int lastDayOfMonth = startDate.dayOfMonth().withMaximumValue().getDayOfMonth();
if (lastDayOfMonth == fixedDaysInMonth) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if is not even needed because your else would return daysBetween in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but I do not follow this comment, which if statement are you referring to?

Copy link
Member

@sbrossie sbrossie Jan 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one on line 99 above my comment. What I am saying is that:

if (lastDayOfMonth == fixedDaysInMonth) {
    return daysBetween;
        } else {
    return daysBetween - (lastDayOfMonth - fixedDaysInMonth);
}

Is the same as: return daysBetween - (lastDayOfMonth - fixedDaysInMonth); so we could simplify - no need for if ... else

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, fixed in 6f6206c

if (lastDayOfMonth == fixedDaysInMonth) {
return daysBetween;
} else {
return daysBetween - (lastDayOfMonth - fixedDaysInMonth);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 🎉 that it works for both when lastDayOfMonth > fixedDaysInMonth or the reverse (and even the equality has commented above).

this.isBuilt = false;
this.allExistingItems = new LinkedList<InvoiceItem>();
this.pendingItemAdj = new LinkedList<InvoiceItem>();
this.invoiceConfig = invoiceConfig;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar remark as for the class InvoiceDateUtils. Here we don't offer static method, but these objects are created on the fly with request parameters, and I think it would be best to mix the InvoiceConfig - not that most methods would not be available anyways because they need a context, which we don't pass. So here, instead I suggest to pass the integer for prorationFixedDays.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I've updated AccountItemTree (and the other related classes) to accept prorationFixedDays instead of invoiceConfig.

final InvoicePruner invoicePruner = new InvoicePruner(existingInvoices);
final Set<UUID> toBeIgnored = invoicePruner.getFullyRepairedItemsClosure();
final AccountItemTree accountItemTree = new AccountItemTree(account.getId(), invoiceId);
final AccountItemTree accountItemTree = new AccountItemTree(account.getId(), invoiceId, config.getProrationFixedDays());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ We need to call the version of the config API that takes a context - whenever, we offer a version that takes a context, it needs to be used. Unfortunately, we don't have a way to statically check for this, so this requires careful attention in the code review... Could you make sure we only use this version for src/main files - for tests, it's ok to use the other form.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 6f6206c

@reshmabidikar reshmabidikar merged commit e954354 into killbill:master Jan 31, 2024
@reshmabidikar reshmabidikar deleted the fixed-proration-2 branch January 28, 2025 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants