README.md
# Billing Cycle
[![Build Status](https://travis-ci.org/simplymadeapps/billing_cycle.svg?branch=master)](https://travis-ci.org/simplymadeapps/billing_cycle)
[![Code Climate](https://codeclimate.com/github/simplymadeapps/billing_cycle/badges/gpa.svg)](https://codeclimate.com/github/simplymadeapps/billing_cycle)
[![Test Coverage](https://codeclimate.com/github/simplymadeapps/billing_cycle/badges/coverage.svg)](https://codeclimate.com/github/simplymadeapps/billing_cycle/coverage)
[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/simplymadeapps/billing_cycle/)
Billing Cycle is a gem used to calculate the billing due dates and time elapsed/remaining in
a recurring subscription's billing cycle.
## Installation
Add this line to your application's Gemfile:
```ruby
gem "billing_cycle"
```
And then execute:
```bash
$ bundle
```
## Usage
### Due Dates
Calculating due dates requires the original billing date as an anchor to determine due dates
in the future. `BillingCycle::BillingCycle` does the work to handle edge cases like having
a monthly subscription that started on the 31st when there's not 31 days in every month.
```ruby
original_billing_date = Time.zone.parse("2018-01-31 00:00:00")
billing_interval = 1.month
billing_cycle = BillingCycle::BillingCycle.new(original_billing_date, billing_interval)
Time.zone.now
# => Tue, 26 Jun 2018 00:00:00 CDT -05:00
billing_cycle.next_due_at
# => Sat, 30 Jun 2018 00:00:00 CDT -05:00
billing_cycle.previous_due_at
# => Thu, 31 May 2018 00:00:00 CDT -05:00
```
A time can be passed in as "now" instead of implicitly using the current time.
```ruby
billing_cycle.next_due_at(Time.zone.parse("2020-02-01 00:00:00")
# => Sat, 29 Feb 2020 00:00:00 CST -06:00
billing_cycle.previous_due_at(Time.zone.parse("2020-02-01 00:00:00")
# => Fri, 31 Jan 2020 00:00:00 CST -06:00
```
If the original billing date is in the future, the `next_due_at` will always be the
original billing date, and the `previous_due_at` will be `nil`.
```ruby
original_billing_date = Time.zone.parse("9999-12-31 00:00:00")
billing_interval = 1.month
billing_cycle = BillingCycle::BillingCycle.new(original_billing_date, billing_interval)
billing_cycle.next_due_at
# => Fri, 31 Dec 9999 00:00:00 CST -06:00
billing_cycle.previous_due_at
# => nil
```
### Time Elapsed and Remaining
The time elapsed and remaining can be used for displaying how much time has been used
and how much time is left in a billing cycle.
```ruby
original_billing_date = Time.zone.parse("2019-06-01 00:00:00")
billing_interval = 1.month
billing_cycle = BillingCycle::BillingCycle.new(original_billing_date, billing_interval)
Time.zone.now
# => Sun, 16 Jun 2019 00:00:00 CDT -05:00
billing_cycle.time_elapsed
# => 1296000.0 (seconds)
billing_cycle.time_remaining
# => 1296000.0 (seconds)
```
An interval can be passed in instead of implicitly using seconds and time can be passed in as "now"
instead of implicitly using the current time.
```ruby
billing_cycle.time_elapsed(1.day, Time.zone.parse("2019-06-07 00:00:00"))
# => 6.0 (days)
billing_cycle.time_remaining(1.day, Time.zone.parse("2019-06-07 00:00:00"))
# => 24.0 (days)
```
### Percent Elapsed and Remaining
The percent elapsed and remaining can be used for calculating subscription pricing when charging
or refunding for a partial billing cycle. The percentages are returned as a fraction of 1.0.
```ruby
original_billing_date = Time.zone.parse("2019-06-01 00:00:00")
billing_interval = 1.month
billing_cycle = BillingCycle::BillingCycle.new(original_billing_date, billing_interval)
Time.zone.now
# => Sun, 16 Jun 2019 00:00:00 CDT -05:00
billing_cycle.percent_elapsed
# => 0.5
billing_cycle.percent_remaining
# => 0.5
```
A time can be passed in as "now" instead of implicitly using the current time.
```ruby
billing_cycle.percent_elapsed(Time.zone.parse("2019-06-07 00:00:00"))
# => 0.2
billing_cycle.percent_remaining(Time.zone.parse("2019-06-07 00:00:00"))
# => 0.8
```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).