Dolibarr / dolibarr

Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.
https://www.dolibarr.org
GNU General Public License v3.0
5.47k stars 2.8k forks source link

End of month incorrect (clone salary) #31798

Open mdeweerd opened 2 days ago

mdeweerd commented 2 days ago

Bug

Detected in 19.0.2, but still valid in online demo (20.0.1).

I cloned the latest salary entry, chose to update the "END DATE" with the proposed link, and I get 1998:

https://demo.dolibarr.org/salaries/card.php?action=clone&token=9a96d666924ec0e685d205c00fddfbc4&id=182

{AE7E402B-830D-4277-A1E2-089AFDC0B7A1}

Dolibarr Version

demo.dolibarr.org

Environment PHP

No response

Environment Database

No response

Steps to reproduce the behavior and expected behavior

No response

Attached files

No response

sonikf commented 1 day ago

Hi @mdeweerd I can confirm your finding. Can you test this patch with a warning that Start date must be filled first?

$formconfirm .= "<script>
        $('#clone_date_end').after($('<button id=\"fill_end_of_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('FillEndOfMonth')."</button>'));
        $('#fill_end_of_month').click(function(){
                var clone_date_startmonth = +$('#clone_date_startmonth').val();
                var clone_date_startyear = +$('#clone_date_startyear').val();
                if (!clone_date_startmonth || !clone_date_startyear) {
                        alert('".$langs->trans("Please set the Start date first")."');
                        return;
                }
                var end_date = new Date(clone_date_startyear, clone_date_startmonth, 0);
                // Format the date and set the values in the input fields
                $('#clone_date_end').val(formatDate(end_date,'".$langs->trans("FormatDateShortJavaInput")."'));
                $('#clone_date_endday').val(end_date.getDate());
                $('#clone_date_endmonth').val(end_date.getMonth() + 1);
                $('#clone_date_endyear').val(end_date.getFullYear());
        });
</script>";
mdeweerd commented 1 day ago

@sonikf Before testing the patch, maybe we can complete the functionnality.

I would not produce an error, but show a good end date even if the start date is empty.

As we are cloning another payment, my expectations would be:

sonikf commented 1 day ago

@mdeweerd As per your request Can you test?

$formconfirm .= "<script>
    // Buttons for start date: previous month, current month, previous week, current week
    $('#clone_date_start').after(
        $('<button id=\"start_prev_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('PrevMonth')."</button>')
        .add('<button id=\"start_curr_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('CurrMonth')."</button>')
        .add('<button id=\"start_prev_week\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('PrevWeek')."</button>')
        .add('<button id=\"start_curr_week\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('CurrWeek')."</button>')
    );

    // Start date
    $('#start_prev_month').click(function(){
        var now = new Date();
        var startPrevMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
        setStartDate(startPrevMonth);
    });

    $('#start_curr_month').click(function(){
        var now = new Date();
        var startCurrMonth = new Date(now.getFullYear(), now.getMonth(), 1);
        setStartDate(startCurrMonth);
    });

    $('#start_prev_week').click(function(){
        var now = new Date();
        var startPrevWeek = new Date(now.setDate(now.getDate() - now.getDay() - 7));
        startPrevWeek.setDate(startPrevWeek.getDate() + 1); // Adjust to Monday
        setStartDate(startPrevWeek);
    });

    $('#start_curr_week').click(function(){
        var now = new Date();
        var startCurrWeek = new Date(now.setDate(now.getDate() - now.getDay() + 1)); // This will set the date to Monday of current week
        setStartDate(startCurrWeek);
    });

    function setStartDate(date) {
        $('#clone_date_start').val(formatDate(date, '".$langs->trans("FormatDateShortJavaInput")."'));
        $('#clone_date_startday').val(date.getDate());
        $('#clone_date_startmonth').val(date.getMonth() + 1);
        $('#clone_date_startyear').val(date.getFullYear());
    }

    // Button to fill end of month
    $('#clone_date_end').after($('<button id=\"fill_end_of_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:1px;\" type=\"button\">".$langs->trans('FillEndOfMonth')."</button>'));

    // End of month
    $('#fill_end_of_month').click(function(){
        var clone_date_startmonth = +$('#clone_date_startmonth').val();
        var clone_date_startyear = +$('#clone_date_startyear').val();

        var end_date;

        if (clone_date_startmonth && clone_date_startyear) {
            end_date = new Date(clone_date_startyear, clone_date_startmonth, 0);
        } else {
            var currentDate = new Date();
            var currentDay = currentDate.getDate();
            if (currentDay <= 15) {
                end_date = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0);
            } else {
                end_date = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
            }
        }

        $('#clone_date_end').val(formatDate(end_date, '".$langs->trans("FormatDateShortJavaInput")."'));
        $('#clone_date_endday').val(end_date.getDate());
        $('#clone_date_endmonth').val(end_date.getMonth() + 1);
        $('#clone_date_endyear').val(end_date.getFullYear());
    });
</script>";
mdeweerd commented 1 day ago

@sonikf Nice - The new links work, the computation of the end date is good. However, the start of the period is empty when opening and it would be logical to have that at the end of the cloned period + 1 day.

sonikf commented 1 day ago

You mean Start date auto filled?

mdeweerd commented 1 day ago

Yes. If the cloned record has an end date.

sonikf commented 1 day ago

@mdeweerd It is done! I'll submit fix for v.19 with only button fix because @eldy will not accept new code in older versions and then i will submit to develop full code.

        $formquestion = array(
            array('type' => 'text', 'name' => 'clone_label', 'label' => $langs->trans("Label"), 'value' => $langs->trans("CopyOf").' '.$object->label),
        );

        //$formquestion[] = array('type' => 'date', 'name' => 'clone_date_ech', 'label' => $langs->trans("Date"), 'value' => -1);
        if (!empty($object->dateep)) {
            $formquestion[] = array('type' => 'date', 'name' => 'clone_date_start', 'label' => $langs->trans("DateStart"), 'value' => ($object->dateep) + 86400);
        } else {
            $formquestion[] = array('type' => 'date', 'name' => 'clone_date_start', 'label' => $langs->trans("DateStart"), 'value' => -1);
        }           
        $formquestion[] = array('type' => 'date', 'name' => 'clone_date_end', 'label' => $langs->trans("DateEnd"), 'value' => -1);
        $formquestion[] = array('type' => 'text', 'name' => 'amount', 'label' => $langs->trans("Amount"), 'value' => price($object->amount), 'morecss' => 'width100 right');

        $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneSalary', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 280);

        //Add fill with end of month button

$formconfirm .= "<script>
    // Buttons for start date: previous month, current month, previous week, current week
    $('#clone_date_start').after(
        $('<button id=\"start_prev_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('PrevMonth')."</button>')
        .add('<button id=\"start_curr_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('CurrMonth')."</button>')
        .add('<button id=\"start_prev_week\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('PrevWeek')."</button>')
        .add('<button id=\"start_curr_week\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:4px;\" type=\"button\">".$langs->trans('CurrWeek')."</button>')
    );

    // Start date
    $('#start_prev_month').click(function(){
        var now = new Date();
        var startPrevMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
        setStartDate(startPrevMonth);
    });

    $('#start_curr_month').click(function(){
        var now = new Date();
        var startCurrMonth = new Date(now.getFullYear(), now.getMonth(), 1);
        setStartDate(startCurrMonth);
    });

    $('#start_prev_week').click(function(){
        var now = new Date();
        var startPrevWeek = new Date(now.setDate(now.getDate() - now.getDay() - 7));
        startPrevWeek.setDate(startPrevWeek.getDate() + 1); 
        setStartDate(startPrevWeek);
    });

    $('#start_curr_week').click(function(){
        var now = new Date();
        var startCurrWeek = new Date(now.setDate(now.getDate() - now.getDay() + 1)); 
        setStartDate(startCurrWeek);
    });

    function setStartDate(date) {
        $('#clone_date_start').val(formatDate(date, '".$langs->trans("FormatDateShortJavaInput")."'));
        $('#clone_date_startday').val(date.getDate());
        $('#clone_date_startmonth').val(date.getMonth() + 1);
        $('#clone_date_startyear').val(date.getFullYear());
    }

    // Button to fill end of month
    $('#clone_date_end').after($('<button id=\"fill_end_of_month\" class=\"dpInvisibleButtons\" style=\"color: var(--colortextlink);font-size: 0.8em;opacity: 0.7;margin-left:1px;\" type=\"button\">".$langs->trans('FillEndOfMonth')."</button>'));

    // End of month
    $('#fill_end_of_month').click(function(){
        var clone_date_startmonth = +$('#clone_date_startmonth').val();
        var clone_date_startyear = +$('#clone_date_startyear').val();

        var end_date;

        if (clone_date_startmonth && clone_date_startyear) {
            end_date = new Date(clone_date_startyear, clone_date_startmonth, 0);
        } else {
            var currentDate = new Date();
            var currentDay = currentDate.getDate();
            if (currentDay <= 15) {
                end_date = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0);
            } else {
                end_date = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
            }
        }

        $('#clone_date_end').val(formatDate(end_date, '".$langs->trans("FormatDateShortJavaInput")."'));
        $('#clone_date_endday').val(end_date.getDate());
        $('#clone_date_endmonth').val(end_date.getMonth() + 1);
        $('#clone_date_endyear').val(end_date.getFullYear());
    });
</script>";
mdeweerd commented 1 day ago

Thank you. - we'll see the full functionnality in 21.0.

I had a look at the code and wanted to point out that adding 86400 seconds is not the best way to add one day - because of the summer and winter time changes that could sometimes mean 2 days and 0 days. I think that the date.lib has a helper function for this kind of offset.

Anyway, I tested the code as is and the start date was filled in as expected for this month.

sonikf commented 1 day ago

I had a look at the code and wanted to point out that adding 86400 seconds is not the best way to add one day - because of the summer and winter time changes that could sometimes mean 2 days and 0 days. I think that the date.lib has a helper function for this kind of offset.

I' ll look into it..

At your service Thank you for your great work!