Topic: Whats happened with Recurrent invoices?

Hi,

Recurrent invoices used to work as per the wiki.

But now when I enter 5 in days and 1 in month, the invoice does not produce a invoice on the 5th of every month, instead it produces an invoice every 1 month and five days? And other not so useful billing dates can also be made.

Trying to look back when changes were made, but I cannot see them.

2.4.3 clean install, default theme

Re: Whats happened with Recurrent invoices?

This was changed in FA 2.3.5 as stated in the wiki.

Re: Whats happened with Recurrent invoices?

Thanks Apmuthu.

Re: Whats happened with Recurrent invoices?

@apmuthu, I've tested against the latest wiki entries and it still is not fuctioning as stated in the wiki.

Please try a few entries and you should see the problem.

Re: Whats happened with Recurrent invoices?

It works okay in 2.4.3+.
The last significant changes to the file sales/create_recurrent_invoices.php that introduced the functions "calculate_from" and "calculate_next" were done between Apr and July 2015 and they compute correctly as per the wiki.

Attached are the screenshots of the Recurrent Sales Invoice Request Form, it's execution and the resultant Invoice generated.

Where in it do you face a problem?

Post's attachments

RecurrentSalesInvoice.zip 36.1 kb, 1 downloads since 2017-12-06 

You don't have the permssions to download the attachments of this post.

6 (edited by poncho1234 12/09/2017 05:18:41 pm)

Re: Whats happened with Recurrent invoices?

@apmuthu Hi...

So as I understand it:-

Choose # of days 7 and leave month at zero and an invoice will be created every week, invoices will start on begin date.

or

Leave days at zero, set months to 1 and an invoice will be created every month dated for the begin date.

And that is the only funtionality now? (the -1 in days no longer works for last day of the month?)

Please confirm this is the only intended functionality?

Also I have made some tests based on this as follows:-

Input to recurrent invoices                        Create and Print Recurrent Invoices   
Name    Days    Monthly    Begin        Invoice #    Invoice date    Recurrent Invoice covers period
Test 1    7    0    01-12-16        1    08-12-16    01/12/2016 - 07/12/2016.
Test 1    7    0    01-12-16        2    15-12-16    08/12/2016 - 14/12/2016.
   "            "    "          "                "           "                        "
Test 1    7    0    01-12-16        12    23-02-17    16/02/2017 - 22/02/2017.
Test 1    7    0    01-12-16        13    02-03-17    23/02/2017 - 01/03/2017.
                           
Test 2    0    1    01-12-16        1    01-01-17    01/12/2016 - 31/12/2016.
Test 2    0    1    01-12-16        2    01-02-17    01/01/2017 - 31/01/2017.
Test 2    0    1    01-12-16        3    01-03-17    01/02/2017 - 28/02/2017.
Test 2    0    1    01-12-16        4    01-04-17    01/03/2017 - 31/03/2017.
                           
Test 3    0    1    05-12-16        1    05-01-17    05/12/2016 - 04/01/2017.
Test 3    0    1    05-12-16        2    05-02-17    05/01/2017 - 04/02/2017.
Test 3    0    1    05-12-16        3    05-03-17    05/02/2017 - 04/03/2017.
                           
Test 4    0    1    29-12-16        1    29-01-17    29/12/2016 - 28/01/2017.
Test 4    0    1    29-12-16        2    28-02-17    29/01/2017 - 27/02/2017.
Test 4    0    1    29-12-16        3    28-03-17    28/02/2017 - 27/03/2017.
                           
Test 5    0    1    31-12-16        1    31-01-17    31/12/2016 - 30/01/2017.
Test 5    0    1    31-12-16        2    28-02-17    31/01/2017 - 27/02/2017.
Test 5    0    1    31-12-16        3    28-03-17    28/02/2017 - 27/03/2017.

Tests 1, 2 & 3 work fine.
In tests 4 & 5 it doesn't seem to handle February very well.

(Somehow I was reading a very old version of the wiki, now with wiki update i get the correct version)

Re: Whats happened with Recurrent invoices?

Month is a calendar month and not 30 days.

Months and days can be used together like 1 month and 7 days.

The functions "add_months" and "add_days" are defined in includes/date_functions.inc.
The functions "days_in_month" and "end_month" are also defined therein.

We can use the native PHP function cal_days_in_month(CAL_GREGORIAN,10,2005); to get the days in a month / end of month. This function has been available since PHP 4.1+. The "-1" can be implemented using these functions.

Lines 79-81 of the function calculate_next():

    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);

can be altered to make for the "-1" functionality of last day of the month as:

if ($myrow['days'] == -1) {
// ignore months when days = -1
    $next = add_days($next, 1);
    $next = end_month($next);
    return $next;
} else {
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}

Please test and provide feedback for inclusion into the core.

Re: Whats happened with Recurrent invoices?

I will test, gimme an hour or so..

But tests 4 & 5 should go back to 29-03-17 & 31-03-17 after February shouldn't they?

Re: Whats happened with Recurrent invoices?

Ok, with updated code =

Test 4a    0    1    29-12-16        1    29-01-17    29/12/2016 - 28/01/2017.
Test 4a    0    1    29-12-16        2    28-02-17    29/01/2017 - 27/02/2017.
Test 4a    0    1    29-12-16        3    28-03-17    28/02/2017 - 27/03/2017.
                           
Test 5a    0    1    31-12-16        1    31-01-17    31/12/2016 - 30/01/2017.
Test 5a    0    1    31-12-16        2    28-02-17    31/01/2017 - 27/02/2017.
Test 5a    0    1    31-12-16        3    28-03-17    28/02/2017 - 27/03/2017.
                           
Test 6    -1    1    01-12-16        1    31-12-16    01/12/2016 - 30/12/2016.
Test 6    -1    1    01-12-16        2    30-01-17    31/12/2016 - 29/01/2017.
Test 6    -1    1    01-12-16        3    27-02-17    30/01/2017 - 26/02/2017.

Re: Whats happened with Recurrent invoices?

If we put in 1 month, then it will be a calendar month. If we put in 30 days, it will be just so using the add_month() function.

The -1 functionality works okay for the first invoice and is 1 day earlier for the rest.

Try to change the 3rd line above:

$next = add_days($next, 1);

to:

$next = add_days($next, 2);

and provide feedback for the "-1" cases.

Re: Whats happened with Recurrent invoices?

so with

//new function calculate_next
function calculate_next($myrow)
{
    if ($myrow['days'] == -1) {
// ignore months when days = -1
    $next = add_days($next, 1);
    $next = end_month($next);
    return $next;
} else {
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}
}

I'm getting:-

Test 7    30    0    01-12-16        1    31-12-16    01/12/2016 - 30/12/2016.
Test 7    30    0    01-12-16        2    30-01-17    31/12/2016 - 29/01/2017.
Test 7    30    0    01-12-16        3    01-03-17    30/01/2017 - 28/02/2017.
                           
Test 8    30    0    31-12-16        1    30-01-17    31/12/2016 - 29/01/2017.
Test 8    30    0    31-12-16        2    01-03-17    30/01/2017 - 28/02/2017.
Test 8    30    0    31-12-16        3    31-03-17    01/03/2017 - 30/03/2017.

Re: Whats happened with Recurrent invoices?

For 30 days it appears okay so we do not need to change that portion.

For -1, the invoice needs to be raised on the last day of the month for the period from the last day of the previous month to the day before the last day of the current month.

The new function replacement should be:

function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1) {
        // ignore months when days = -1
            $next = add_days($next, 2); // <-- changed line
            $next = end_month($next);
            return $next;
    } else {
        $next = add_months($next, $myrow['monthly']);
        $next = add_days($next, $myrow['days']);
        return add_days($next,-1);
    }
}

13 (edited by poncho1234 12/10/2017 08:22:51 pm)

Re: Whats happened with Recurrent invoices?

Ah... !
Ok, will retest with updated function, maybe today, probably tomorrow.

14 (edited by poncho1234 12/11/2017 03:04:50 pm)

Re: Whats happened with Recurrent invoices?

With:-

function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1) {
        // ignore months when days = -1
            $next = add_days($next, 2); // <-- changed line
            $next = end_month($next);
            return $next;
    } else {
        $next = add_months($next, $myrow['monthly']);
        $next = add_days($next, $myrow['days']);
        return add_days($next,-1);
    }
}

I'm getting the following:-
Input to recurrent invoices                        Create and Print Recurrent Invoices   
Name    Days    Monthly    Begin        Invoice #    Invoice date    Recurrent Invoice covers period
Test 1c    7    0    01-12-16        1    08-12-16    01/12/2016 - 07/12/2016.
Test 1c    7    0    01-12-16        2    15-12-16    08/12/2016 - 14/12/2016.
       "    "    "           "        "           "                       "
Test 1c    7    0    01-12-16        12?    23-02-17    16/02/2017 - 22/02/2017.
Test 1c    7    0    01-12-16        13?    02-03-17    23/02/2017 - 01/03/2017.
                           
Test 2c    0    1    01-12-16        1    01-01-17    01/12/2016 - 31/12/2016.
Test 2c    0    1    01-12-16        2    01-02-17    01/01/2017 - 31/01/2017.
Test 2c    0    1    01-12-16        3    01-03-17    01/02/2017 - 28/02/2017.
Test 2c    0    1    01-12-16        4    01-04-17    01/03/2017 - 31/03/2017.
                           
Test 5c    0    1    31-12-16        1    31-01-17    31/12/2016 - 30/01/2017.
Test 5c    0    1    31-12-16        2    28-02-17    31/01/2017 - 27/02/2017.
Test 5c    0    1    31-12-16        3    28-03-17    28/02/2017 - 27/03/2017.
                           
Test 9    -1    0    31-12-16        1    30-12-16    31/12/2016 - 29/12/2016.
Test 9    -1    0    31-12-16        2    29-12-16    30/12/2016 - 28/12/2016.
Test 9    -1    0    31-12-16        3    28-12-16    29/12/2016 - 27/12/2016.

Re: Whats happened with Recurrent invoices?

From the wiki:

A days value of -1 together with a month value would be the last day in the previous month.

Hence we need a month value as well to get the period.

The function that can now be tried is:

function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1 && $myrow['monthly'] > 0) {
        // ignore months when days = -1
        $next = add_days(begin_month($next), -1); // last day of previous month
        $myrow['days']=0;
    }
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}

Re: Whats happened with Recurrent invoices?

function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1 && $myrow['monthly'] > 0) {
        // ignore months when days = -1
            $next = add_days(begin_month($next), -1); // last day of previous month
            $myrow['days']=0;
    }
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}

gives

Test 9d    -1    1    31-12-16        1    30-01-17    31/12/2016 - 29/01/2017.
Test 9d    -1    1    31-12-16        2    27-02-17    30/01/2017 - 26/02/2017.
Test 9d    -1    1    31-12-16        3    26-03-17    27/02/2017 - 25/03/2017.

Re: Whats happened with Recurrent invoices?

Try this now:

function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1 && $myrow['monthly'] > 0) {
        // ignore months when days = -1
            $next = begin_month($next); // to later become last day of previous month
            $myrow['days']=0;
    }
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}

Re: Whats happened with Recurrent invoices?

//new function calculate_next
function calculate_next($myrow)
{
    if ($myrow["last_sent"] == '0000-00-00')
        $next = sql2date($myrow["begin"]);
    else
        $next = sql2date($myrow["last_sent"]);
    if ($myrow['days'] == -1 && $myrow['monthly'] > 0) {
        // ignore months when days = -1
            $next = begin_month($next); // to later become last day of previous month
            $myrow['days']=0;
    }
    $next = add_months($next, $myrow['monthly']);
    $next = add_days($next, $myrow['days']);
    return add_days($next,-1);
}

is giving the same result

Test 9e    -1    1    31-12-16        1    30-01-17    31/12/2016 - 29/01/2017.
Test 9e    -1    1    31-12-16        2    27-02-17    30/01/2017 - 26/02/2017.
Test 9e    -1    1    31-12-16        3    26-03-17    27/02/2017 - 25/03/2017.

Re: Whats happened with Recurrent invoices?

Shall we code so that:

Test expected    -1    1    31-12-2016        1    31-01-2017    31-12-2016 - 30-01-2017.

The last sent will then become 31-01-2017 ?

20 (edited by poncho1234 12/14/2017 03:52:32 pm)

Re: Whats happened with Recurrent invoices?

We may be getting a little confused with the objective,

The original code (before the above mods) functioned  if 0 for days and 1 or more entered in months, the start date would then be the billing date going forward. So for dates from the 1st - 28th of the month this works fine, but what happens if you want the 29th, 30th or 31st? It all goes wrong in February (unless its a leap year for the 29th), and stays wrong in march onwards.

We can state in the wiki that only start dates to the 28th of the month are permitted, but...?

Re: Whats happened with Recurrent invoices?

The method of date calculation for add_months() has been hardcoded for
1 leap day each 4 years,
1 more leap day each 100 years and
1 less leap day every 400 years.
The number of days each month are looked up in an array in this manner.

This translates into the famous "What day would Christmas be in the year ####" as absolute day of Christmas for a known year + no. of years to required year from known year * 1.2496.

That is why I wanted the Gregorian year php function to be used. Even then I doubt this issue would get solved fully.

Let us first determine what we want for each of the 29 (non leap years), 30, 31 dates.

22 (edited by poncho1234 12/14/2017 09:00:30 pm)

Re: Whats happened with Recurrent invoices?

For me the expected results would be as follows:-

Test 3    0    1    05-12-16        1    05-01-17    05/12/2016 - 04/01/2017.
Test 3    0    1    05-12-16        2    05-02-17    05/01/2017 - 04/02/2017.
Test 3    0    1    05-12-16        3    05-03-17    05/02/2017 - 04/03/2017.
                           
Test 4    0    1    29-12-16        1    29-01-17    29/12/2016 - 28/01/2017.
Test 4    0    1    29-12-16        2    28-02-17    29/01/2017 - 27/02/2017.
Test 4    0    1    29-12-16        3    29-03-17    28/02/2017 - 28/03/2017.
Test 4    0    1    29-12-16        4    29-04-17    29/03/2017 - 28/04/2017.

Test 4    0    1    30-12-16        1    30-01-17    30/12/2016 - 29/01/2017.
Test 4    0    1    30-12-16        2    28-02-17    30/01/2017 - 27/02/2017.
Test 4    0    1    30-12-16        3    30-03-17    28/02/2017 - 29/03/2017.
Test 4    0    1    30-12-16        4    30-04-17    30/03/2017 - 29/04/2017.

Test 4    0    1    31-12-16        1    31-01-17    31/12/2016 - 30/01/2017.
Test 4    0    1    31-12-16        2    28-02-17    31/01/2017 - 27/02/2017.
Test 4    0    1    31-12-16        3    31-03-17    28/02/2017 - 30/03/2017.
Test 4    0    1    31-12-16        4    30-04-17    31/03/2017 - 29/04/2017.
Test 4    0    1    31-12-16        5    31-05-17    30/04/2017 - 30/05/2017.

I think I have that right please check

As I said earlier We can state in the wiki that only start dates to the 28th of the month are permitted

Re: Whats happened with Recurrent invoices?

Also we can make sure that if the Invoice Date becomes 29 to 31 we need to push it to the end of the month if it is invalid (like 31st Feb). That way, can we do away with the "-1" days by always choosing 31st of some valid / invalid month?

Re: Whats happened with Recurrent invoices?

Yes, that sounds good.

Comment: Are 29, 30 & 31 'edge' cases?

Re: Whats happened with Recurrent invoices?

When days = -1 and the day of the last sent date is 29, 30 and 31 which are part of valid dates after computation of $next if they become the last day of that month, this is what is desirable. If however, those $next dates are not valid, then they should be pushed to the last day of that month. The Karnaugh map of this logic on reduction just means irrespective of the day part of the last sent date, just push it to the last day of the computed $next date. he question is that how is the computation of the $next date to be undertaken for edge conditions. The "-1" according to the wiki is just a token to indicate the last date of the previous month as the $next date - so what is the logic needed to code it that way so that it will not have to rely on hindsight.