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/src/API/ReportAPI.php
<?php

namespace PersianWooCommerce\API;

use PersianWooCommerce\Services\ReportService;
use WP_REST_Request;
use WP_REST_Server;

class ReportAPI extends RestAPI {

	public ReportService $service;

	public function __construct() {
		parent::__construct();

		$this->service = new ReportService();
	}

	public function register_routes() {
		/**
		 * Revenue
		 */
		register_rest_route( 'persian-woocommerce/reports', 'revenue/debug', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_debug_report' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => $this->date_args(),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'revenue/summary', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => $this->date_args(),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'revenue/orders', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->date_args(), $this->paginate_args() ),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'revenue/chart', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => $this->date_args(),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'revenue/top-sellers', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => $this->date_args(),
		] );

		/**
		 * Customers
		 */
		register_rest_route( 'persian-woocommerce/reports', 'customer/summary', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->date_args(), $this->paginate_args() ),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'customer/chart', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => $this->date_args(),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'customer/users', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->date_args(), $this->paginate_args(), $this->list_args() ),
		] );

		/**
		 * Stock
		 */
		register_rest_route( 'persian-woocommerce/reports', 'stock/summary', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->stock_args() ),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'stock/products', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->stock_args(), $this->paginate_args() ),
		] );

		register_rest_route( 'persian-woocommerce/reports', 'stock/export', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_reports' ],
			'permission_callback' => [ $this, 'permission_callback' ],
			'args'                => array_merge( $this->stock_args() ),
		] );
	}

	public function permission_callback( WP_REST_Request $request ): bool {

		if ( ( 'yes' !== get_option( "woocommerce_custom_orders_table_enabled" ) ) ) {
			self::response( false, 'برای استفاده از گزارشات ووکامرس فارسی، قابلیت HPOS ووکامرس را فعال نمایید.' );
		}

		if ( 'yes' !== get_option( 'woocommerce_analytics_enabled' ) ) {
			self::response( false, 'قابلیت تجزیه و تحلیل ووکامرس غیرفعال است.' );
		}

		return parent::permission_callback( $request );
	}

	private function stock_args(): array {
		return [
			'status' => [
				'required'          => false,
				'type'              => 'string',
				'description'       => 'Retrieve products with specific stock status.',
				'validate_callback' => fn( $value ) => in_array( $value, [
					'instock',
					'outofstock',
					'lowstock',
					'onbackorder',
				], true ),
				'sanitize_callback' => fn( $value ) => strtolower( sanitize_text_field( $value ) ),
			],
		];
	}

	private function date_args(): array {
		return [
			'from_date' => [
				'required'          => true,
				'type'              => 'integer',
				'description'       => 'Start date (Unix timestamp, Y-m-d 00:00:00)',
				'validate_callback' => fn( $value ) => is_numeric( $value ) && intval( $value ) > 0,
				'sanitize_callback' => fn( $value ) => intval( $value ),
			],
			'to_date'   => [
				'required'          => true,
				'type'              => 'integer',
				'description'       => 'End date (Unix timestamp, Y-m-d 23:59:59)',
				'validate_callback' => fn( $value ) => is_numeric( $value ) && intval( $value ) > 0,
				'sanitize_callback' => fn( $value ) => intval( $value ),
			],
			'interval'  => [
				'required'          => false,
				'type'              => 'string',
				'description'       => 'Batch interval: day, week, month, quarter, year',
				'validate_callback' => fn( $value ) => in_array( $value, [
					'day',
					'week',
					'month',
					'quarter',
					'year',
				], true ),
				'sanitize_callback' => fn( $value ) => sanitize_text_field( $value ),
			],
		];
	}

	private function paginate_args(): array {
		return [
			'page'     => [
				'description'       => 'Current page of the collection.',
				'type'              => 'integer',
				'default'           => 1,
				'sanitize_callback' => 'absint',
				'validate_callback' => fn( $value ) => is_numeric( $value ) && (int) $value > 0,
			],
			'per_page' => [
				'description'       => 'Maximum number of items to be returned in result set.',
				'type'              => 'integer',
				'default'           => 25,
				'sanitize_callback' => 'absint',
				'validate_callback' => fn( $value ) => is_numeric( $value ) && (int) $value > 0,
			],
		];
	}

	private function list_args(): array {
		return [
			'orderby' => [
				'required'          => false,
				'type'              => 'string',
				'description'       => 'Sort collection by a specific attribute.',
				'validate_callback' => fn( $value ) => sanitize_text_field( $value ),
				'sanitize_callback' => fn( $value ) => sanitize_text_field( $value ),
			],
			'order'   => [
				'required'          => false,
				'type'              => 'string',
				'description'       => 'Order sort attribute ascending or descending.',
				'validate_callback' => fn( $value ) => in_array( strtolower( $value ), [ 'asc', 'desc' ], true ),
				'sanitize_callback' => fn( $value ) => strtolower( sanitize_text_field( $value ) ),
			],
		];
	}

	/**
	 * @throws \Exception
	 */
	private function prepare_dates( WP_REST_Request $request ): array {
		$from_date = $request->get_param( 'from_date' );
		$to_date   = $request->get_param( 'to_date' );

		$timezone = wp_timezone_string();

		$from_date = verta()
			->timestamp( $from_date )
			->timezone( $timezone )
			->startDay();

		$to_date = verta()
			->timestamp( $to_date )
			->timezone( $timezone )
			->endDay();

		if ( $from_date->gt( $to_date ) ) {
			throw new \Exception( 'تاریخ شروع نباید پس از تاریخ پایان باشد.' );
		}

		return [ $from_date, $to_date ];
	}


	public function handle_debug_report( WP_REST_Request $request ) {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );
		$interval = sanitize_text_field( $request->get_param( 'interval' ) );

		$data = $this->service->debug_revenue( $start_date, $end_date, $interval );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.', [] );
		}

		self::response( true, '' );
	}

	public function handle_reports( WP_REST_Request $request ) {
		$allowed = [
			'revenue/summary',
			'revenue/top-sellers',
			'revenue/orders',
			'revenue/chart',

			'customer/summary',
			'customer/users',
			'customer/chart',

			'stock/summary',
			'stock/products',
			'stock/export',
		];

		$endpoint = str_replace( 'persian-woocommerce/reports/', '', trim( $request->get_route(), '/' ) );

		if ( ! in_array( $endpoint, $allowed, true ) ) {
			self::response( false, 'مسیر درخواستی شما وجود ندارد.' );
		}

		$method = str_ireplace( [ '-', '/' ], '_', $endpoint ) . '_report';

		if ( ! method_exists( $this, $method ) ) {
			self::response( false, 'شیوه اجرای عملیات دریافت اطلاعات وجود ندارد.' );
		}

		try {
			/** @var array $data */
			$data = $this->{$method}( $request );
		} catch ( \Exception $e ) {
			self::response( false, $e->getMessage() );
		}

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function revenue_summary_report( WP_REST_Request $request ): ?array {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );

		$data = $this->service->revenue_summary( $start_date, $end_date );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function revenue_orders_report( WP_REST_Request $request ): ?array {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );
		$interval = sanitize_text_field( $request->get_param( 'interval' ) );
		$page     = $request->get_param( 'page' );
		$per_page = $request->get_param( 'per_page' );

		$data = $this->service->revenue_orders( $start_date, $end_date, $interval, $per_page, $page );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function revenue_chart_report( WP_REST_Request $request ): ?array {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );
		$interval = sanitize_text_field( $request->get_param( 'interval' ) );

		$data = $this->service->revenue_chart( $start_date, $end_date, $interval );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function revenue_top_sellers_report( WP_REST_Request $request ): ?array {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );

		$data = $this->service->revenue_top_sellers( $start_date, $end_date );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function customer_summary_report( WP_REST_Request $request ) {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );
		$interval = sanitize_text_field( $request->get_param( 'interval' ) );

		$data = $this->service->customer_summary( $start_date, $end_date, $interval );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function customer_chart_report( WP_REST_Request $request ) {
		[ $start_date, $end_date ] = $this->prepare_dates( $request );
		$interval = sanitize_text_field( $request->get_param( 'interval' ) );

		$data = $this->service->customer_chart( $start_date, $end_date, $interval );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function customer_users_report( WP_REST_Request $request ) {

		[ $start_date, $end_date ] = $this->prepare_dates( $request );

		$per_page = intval( $request->get_param( 'per_page' ) );
		$page     = intval( $request->get_param( 'page' ) );
		$orderby  = $request->get_param( 'orderby' );
		$order    = $request->get_param( 'order' );

		$data = $this->service->customer_users( $start_date, $end_date, $per_page, $page, $orderby, $order );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function stock_summary_report( WP_REST_Request $request ) {
		$data = $this->service->stock_summary();

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $this->service->stock_summary() );
	}

	public function stock_products_report( WP_REST_Request $request ) {
		$status   = $request->get_param( 'status' );
		$page     = $request->get_param( 'page' );
		$per_page = $request->get_param( 'per_page' );
		$data     = $this->service->stock_products( $status, $per_page, $page );

		if ( empty( $data ) ) {
			self::response( true, 'داده ای وجود ندارد.' );
		}

		self::response( true, '', $data );
	}

	public function stock_export_report( WP_REST_Request $request ) {
		$this->service->stock_export( $request->get_param( 'status' ) );
	}
}