HEX
Server: LiteSpeed
System: Linux mail.aatilis.ir 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: www (1000)
PHP: 8.3.30
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: /www/wwwroot/soqatland.com/wp-content/plugins/persian-woocommerce/assets/js/pages/revenue.js
//Alpine
document.addEventListener('alpine:init', () => {

    Alpine.data("revenue", ()=>({

        namePage: null,

        revenue: {
            loading: false,
            current: {
                data: null,
                filters: {
                    from_data: null,
                    to_date: null,
                }
            },
            previous: {
               data: null,
                filters: {
                    from_data: null,
                    to_date: null,
                }
            }
        },

        chart:{
            loading: false,
            current: null,
            previous: null,
            filters: {
                interval: {
                    label: 'روز',
                    value: 'day'
                },
                type: {
                    label: 'درآمد ناخالص',
                    value: 'total_sales'
                }
            },
            intervals:[
                {
                    label: 'روز',
                    value: 'day'
                },
                {
                    label: 'هفته',
                    value: 'week'
                },
                {
                    label: 'ماه',
                    value: 'month'
                },
                {
                    label: 'سال',
                    value: 'year'
                }
            ],
            types: [
                {
                    label: 'درآمد ناخالص',
                    value: 'total_sales'
                },
                {
                    label: 'درآمد خالص',
                    value: 'net_sales'
                }
            ]
        },

        topSellers: {
            loading: false,
            filters: {
                type: 'product', //product or category
            },
            products: {
                items: [],
                max: 0
            },
            categories: {
                items: [],
                max: 0
            },
        },

        date:{
            today: null,
            type: 'range', //quick
            comparison: 'year', //period
            range: {
                from: null,
                to: null,
            },
            previousRange: {
                from: null,
                to: null,
            },
            quick: {
                items: [],
                selected: null,
            }
        },

        table: {
            data: [],
            loading: false,
            filters: {
                page: 1,
                per_page: 20
            },
            pagination: {
                items: [],
                currentPage: 1,
                totalPage: 0,
            }
        },

        modals: {
            rangeDate:{
                active: false
            }
        },

        async init(){
            this.date.today = new persianDate();
            this.date.quick.items = pwCreateQuickSelectDateItems(this.date.today);

            await this.getPageData();

            pwLoadTippyInPage();

            //initial date picker
            const tempFromDate = this.revenue.current.filters.from_date ? this.revenue.current.filters.from_date  : this.date.today;
            const tempToDate = this.revenue.current.filters.to_date ? this.revenue.current.filters.to_date : this.date.today;
            const [rangeDateFrom, rangeDateTo] = pwCreateRangeDateFilter(document.getElementById("rangeDateFilter"), tempFromDate, tempToDate)
            this.date.range.from = rangeDateFrom;
            this.date.range.to = rangeDateTo;
        },

        //request functions
        async getPageData() {

            const queryString = pwParseQueryString(window.location.href);
            this.namePage = queryString.page || null;
            delete queryString.page;
            delete queryString.per_page;

            if(queryString.comparison && (queryString.comparison === 'period' || queryString.comparison === 'year')){
                this.date.comparison = queryString.comparison;
            }

            for (const objKey in queryString) {
                if (objKey === 'from_date' || objKey === 'to_date') {
                    if (pwCheckDateFormatIsValid(queryString[objKey])) {
                        this.revenue.current.filters[objKey] = pwDateToTimestamp(queryString[objKey]);
                    } else {
                        delete queryString[objKey];
                    }
                } else {
                    this.revenue.current.filters[objKey] = queryString[objKey];
                }
            }

            if (!this.revenue.current.filters?.from_date || !this.revenue.current.filters?.to_date || (this.revenue.current.filters?.from_date > this.revenue.current.filters?.to_date)) {
                this.revenue.current.filters.from_date = this.date.today.add('days', -30).unix() * 1000;
                this.revenue.current.filters.to_date = this.date.today.unix() * 1000;
            }

            const filtersObj = pwGenerateFiltersObject({
                ...this.revenue.current.filters,
                comparison: this.date.comparison
            });
            pwSetUrlQueryParams(this.namePage, filtersObj);

            const formDate =  new persianDate(this.revenue.current.filters.from_date);
            const toDate = new persianDate(this.revenue.current.filters.to_date);

            if(this.date.comparison === 'year') {
                this.date.previousRange.from = formDate.add('year', -1);
                this.date.previousRange.to = toDate.add('year', -1)
            }else{
                if(this.date.quick.selected){
                    this.date.previousRange.from = this.date.quick.selected.previousFrom;
                    this.date.previousRange.to = this.date.quick.selected.previousTo;
                }else{
                    const diffDays = -1 * (toDate.diff(formDate, 'days') + 1);
                    this.date.previousRange.from = formDate.add('days', diffDays);
                    this.date.previousRange.to = toDate.add('days', diffDays)
                }
            }

            //console.log(pwFormatDate(this.date.previousRange.from, 'YYYY/MM/DD'));
            //console.log(pwFormatDate(this.date.previousRange.to, 'YYYY/MM/DD'));

            this.revenue.previous.filters.from_date = this.date.previousRange.from.unix() * 1000;
            this.revenue.previous.filters.to_date = this.date.previousRange.to.unix() * 1000;

            await Promise.all([
                this.getTopSellers(),
                this.getSummary(),
                this.getChartData(),
                this.getOrders()
            ])
        },

        async getSummary(){
            this.revenue.loading = true;

            try{
                const [current, previous] = await Promise.all([
                    pwApiRequest('persian-woocommerce/reports/revenue/summary', {
                        method: 'GET',
                        data: pwGenerateFiltersObject(this.revenue.current.filters)
                    }),
                    pwApiRequest('persian-woocommerce/reports/revenue/summary', {
                        method: 'GET',
                        data: pwGenerateFiltersObject(this.revenue.previous.filters)
                    })
                ])

                this.revenue.current.data = [];
                this.revenue.previous.data = [];

                if(current.success && previous.success){
                    this.revenue.current.data = current.data
                    this.revenue.previous.data = previous.data
                }else{
                    pwNotyf.error(current.message ? current.message : 'حطایی رخ داده است!');
                }

                this.revenue.loading = false;

            }catch (error){
                console.error('Error fetching posts:', error);
                this.revenue.loading = false;
            }
        },

        async getTopSellers(){
            this.topSellers.loading = true;

            try{
                const result = await pwApiRequest('persian-woocommerce/reports/revenue/top-sellers', {
                    method: 'GET',
                    data: pwGenerateFiltersObject(this.revenue.current.filters)
                })

                this.topSellers.products.items = [];
                this.topSellers.products.max = 0;
                this.topSellers.categories.items = [];
                this.topSellers.categories.max = 0;

                if(result.success){
                    const {products, categories} = result.data;

                    for (const key in products) {
                        this.topSellers.products.items.push(products[key]);
                        if(this.topSellers.products.max < products[key].count){
                            this.topSellers.products.max = products[key].count;
                        }
                    }
                    this.topSellers.products.items.sort((a, b) => (b.count || 0) - (a.count || 0));

                    for (const key in categories) {
                        this.topSellers.categories.items.push(categories[key]);
                        if(this.topSellers.categories.max < categories[key].count){
                            this.topSellers.categories.max = categories[key].count;
                        }
                    }
                    this.topSellers.categories.items.sort((a, b) => (b.count || 0) - (a.count || 0));

                }else{
                    pwNotyf.error(result.message ? result.message : 'حطایی رخ داده است!');
                }

                this.topSellers.loading = false;

            }catch (error){
                console.error('Error fetching posts:', error);
                this.topSellers.loading = false;
            }
        },

        async getChartData(){
            this.chart.loading = true;

            try{
                const [current, previous] = await Promise.all([
                    pwApiRequest('persian-woocommerce/reports/revenue/chart', {
                        method: 'GET',
                        data: {
                            ...pwGenerateFiltersObject(this.revenue.current.filters),
                            interval: this.chart.filters.interval.value
                        }
                    }),
                    pwApiRequest('persian-woocommerce/reports/revenue/chart', {
                        method: 'GET',
                        data: {
                            ...pwGenerateFiltersObject(this.revenue.previous.filters),
                            interval: this.chart.filters.interval.value
                        }
                    })
                ])

                if(current.success && previous.success){
                    this.chart.current = current.data;
                    this.chart.previous = previous.data;
                    this.drawingChart();
                }else{
                    if(!current.success){
                        pwNotyf.error(current.message ? current.message : 'حطایی رخ داده است!');
                    }
                    if(!previous.success){
                        pwNotyf.error(previous.message ? previous.message : 'حطایی رخ داده است!');
                    }
                }
                this.chart.loading = false;

            }catch (error){
                console.error('Error fetching posts:', error);
                this.chart.loading = false;
            }
        },

        async getOrders(){
            this.table.loading = true;

            try{
                const result = await pwApiRequest('persian-woocommerce/reports/revenue/orders', {
                    method: 'GET',
                    data: {
                        ...pwGenerateFiltersObject(this.revenue.current.filters),
                        ...this.table.filters
                    }
                })

                this.table.data = [];

                if(result.success){
                    const data = result.data;
                    for (const key in data.orders) {
                        this.table.data.push({
                            date: key,
                            ...data.orders[key]
                        });
                    }

                    if(this.table.data.length > 0){
                        this.table.pagination = {
                            currentPage: data.pagination.current_page,
                            totalPage: parseInt((data.pagination.total_items / this. table.filters.per_page)) + 1,
                            items: pwGetVisiblePages({
                                currentPage: data.pagination.current_page,
                                totalPage: parseInt((data.pagination.total_items / this. table.filters.per_page)) + 1
                            })
                        }
                    }
                }else{
                    pwNotyf.error(result.message ? result.message : 'حطایی رخ داده است!');
                }

                this.table.loading = false;

            }catch (error){
                console.error('Error fetching posts:', error);
                this.table.loading = false;
            }
        },

        //other function
        selectDateFilter(from, to){
            const [rangeDateFrom, rangeDateTo] = pwCreateRangeDateFilter(document.getElementById("rangeDateFilter"), from, to)
            this.date.range.from = rangeDateFrom;
            this.date.range.to = rangeDateTo;
        },

        setDateFilter(from = null, to= null){

            this.revenue.current.filters.from_date = this.date.range.from.getState().selected.unixDate;
            this.revenue.current.filters.to_date = this.date.range.to.getState().selected.unixDate;

            if(this.date.quick.selected){
                if(((this.date.quick.selected.from.unix() * 1000 ) !== this.revenue.current.filters.from_date) || ((this.date.quick.selected.to.unix() * 1000 ) !== this.revenue.current.filters.to_date)){
                    this.date.quick.selected = null
                }
            }

            const filtersObj = pwGenerateFiltersObject({
                ...this.revenue.current.filters,
                comparison: this.date.comparison
            });
            pwSetUrlQueryParams(this.namePage, filtersObj);

             this.getPageData()

        },

        clearDateFilter(){
            this.revenue.current.filters.from_date = this.date.today.add('days', -30).unix() * 1000;
            this.revenue.current.filters.to_date = this.date.today.unix() * 1000;

            const filtersObj = pwGenerateFiltersObject({
                ...this.revenue.current.filters,
                comparison: this.date.comparison
            });
            pwSetUrlQueryParams(this.namePage, filtersObj);

            this.date.quick.selected = null;
             this.getPageData()
        },

        drawingChart(){
            const labels = [];
            const currentDataset =  [];
            const previousDataset =  [];

            for (const key in this.chart.current) {
                labels.push(key)
                currentDataset.push(this.chart.current[key][this.chart.filters.type.value]);
            }

            for (const key in this.chart.previous) {
                previousDataset.push(this.chart.previous[key][this.chart.filters.type.value]);
            }

            this.chartData = {
                labels,
                datasets: [
                    {
                        label: 'دوره فعلی',
                        data: currentDataset,
                        borderColor: '#007BFF',
                        borderWidth: 2,
                        gradient: {
                            backgroundColor: {
                                axis: 'y',
                                colors: {
                                    0: 'rgba(0,123,255,0)',
                                    90: 'rgba(0,123,255,0.5)'
                                }
                            }
                        },
                        fill: true,
                        tension: 0.5,
                        cubicInterpolationMode: 'monotone'
                    },
                    {
                        label: 'دوره قبلی',
                        data: previousDataset,
                        borderColor: '#FE6BBA',
                        borderWidth: 2,
                        gradient: {
                            backgroundColor: {
                                axis: 'y',
                                colors: {
                                    0: 'rgba(254,107,186,0)',
                                    90: 'rgba(254,107,186,0.5)'
                                }
                            }
                        },
                        fill: true,
                        tension: 0.5,
                        cubicInterpolationMode: 'monotone'
                    }
                ]
            }
            pwCreateChart(document.getElementById("chart"),  this.chartData);
        },

        compare(oldValue, newValue){

            if(!oldValue && !newValue){
                return `
                    <div class="flex items-center gap-1 text-gray-500 bg-gray-100 rounded-md text-xs cursor-pointer py-1 px-2">
                        <span dir="ltr">0%</span>
                    </div>
                `
            }

            oldValue = (typeof oldValue === 'undefined') ? 0 : oldValue;
            newValue = (typeof newValue === 'undefined') ? 0 : newValue;

            let changeAmount = 0;
            if(oldValue === 0){
                changeAmount = ((newValue - oldValue) * 100 );
            }else{
                changeAmount = (((newValue - oldValue) * 100 ) / oldValue);
            }

            if(changeAmount === 0){
                return `
                    <div class="flex items-center gap-1 text-gray-500 bg-gray-100 rounded-md text-xs cursor-pointer py-1 px-2">
                        <span dir="ltr">0%</span>
                    </div>
                `
            }else if(changeAmount > 0){
                return `
                    <div class="flex items-center gap-1 text-positive-state bg-positive-state/10 rounded-md text-xs cursor-pointer py-1 px-2">
                        <span dir="ltr">+${Number(changeAmount.toFixed(2))}%</span>
                        <img src="${pwAssetsFolder}/images/icons/ascending.svg">
                    </div>
                `
            }else{
                return `
                    <div class="flex items-center gap-1 text-warning-state bg-warning-state/10 rounded-md text-xs cursor-pointer py-1 px-2">
                        <span dir="ltr">${Number(changeAmount.toFixed(2))}%</span>
                        <img src="${pwAssetsFolder}/images/icons/descending.svg">
                    </div>
                `
            }
        },

        changePage(newPage){
            this.table.pagination.currentPage = newPage;
            this.table.filters.page = newPage;
            this.getOrders();
        }

    }))

})