<?php
# @Last modified time: 2022/10/15 13:44:52
namespace peproulitmateinvoice;
use voku\CssToInlineStyles\CssToInlineStyles;

defined("ABSPATH") or die("Pepro Ultimate Invoice :: Unauthorized Access!");

if (!class_exists("PeproUltimateInvoice_Print")) {
    class PeproUltimateInvoice_Print
    {
        protected $td;
        protected $fn;
        protected $parent;
        protected $hide_bundles_parent;
        protected $hide_bundles_child;
        protected $_woosb_show_bundles;
        protected $_woosb_show_bundles_subtitle;
        protected $_woosb_show_bundled_products;
        protected $_woosb_show_bundled_subtitle;
        protected $_woosb_show_bundled_hierarchy;
        protected $_woosb_show_bundled_prefix;
        protected $_woosb_show_bundles_prefix;
        public function __construct()
        {
            $this->td = "pepro-ultimate-invoice";
            global $PeproUltimateInvoice;
            $this->parent = $PeproUltimateInvoice;
            $this->fn = new PeproUltimateInvoice_Template;

            add_filter( "puiw_get_default_dynamic_params", array( $this, "puiw_get_default_dynamic_params"), 10, 2);
            // add compatibility with WPC Product Bundles for WooCommerce By WPClever
            $this->hide_bundles_parent = 0;
            $this->hide_bundles_child = 0;

            $this->_woosb_show_bundles           = $this->fn->get_woosb_show_bundles();
            $this->_woosb_show_bundles_subtitle  = $this->fn->get_woosb_show_bundles_subtitle();
            $this->_woosb_show_bundled_products  = $this->fn->get_woosb_show_bundled_products();
            $this->_woosb_show_bundled_subtitle  = $this->fn->get_woosb_show_bundled_subtitle();
            $this->_woosb_show_bundled_hierarchy = $this->fn->get_woosb_show_bundled_hierarchy();
            $this->_woosb_show_bundled_prefix    = $this->fn->get_woosb_bundled_subtitle_prefix(_x("Bundled in:", "wc-setting", $this->td));
            $this->_woosb_show_bundles_prefix    = $this->fn->get_woosb_bundles_subtitle_prefix(_x("Bundled products:", "wc-setting", $this->td));
            add_filter( "puiw_order_items", array($this, "puiw_sort_order_items"), 2, 2);
            if ($this->_woosb_show_bundles == "no"){
              add_filter( "puiw_order_items", array($this, "woosb_puiw_hide_bundles_parent"), 10, 2);
            }
            if ($this->_woosb_show_bundled_products == "no"){
              add_filter( "puiw_order_items", array($this, "woosb_puiw_hide_bundled_childs"), 10, 2);
            }
            add_action( "woocommerce_before_order_itemmeta", array( $this, "woosb_before_order_item_meta" ), 10, 1 );
            add_filter( "puiw_invoice_item_extra_classes",   array($this, "puiw__item_extra_classes"), 10, 6);
            add_filter( "puiw_get_custom_css_style",         array($this, "custom_css_per_invoice"), 10, 2);
            add_filter( "puiw_get_pdf_css_style",            array($this, "custom_css_per_invoice"), 10, 2);
            add_filter( "puiw_get_inventory_css_style",      array($this, "custom_css_per_invoice"), 10, 2);
        }
        public function puiw_get_default_dynamic_params($opts, $order)
        {

          if ( isset($_GET["tp"]) && !empty($_GET["tp"]) ){
            $opts["template"] = sanitize_text_field(base64_decode(urldecode($_GET["tp"])));
            $opts["preinvoice_template"] = sanitize_text_field(base64_decode(urldecode($_GET["tp"])));
          }

          if ( isset($_GET["pclr"]) && !empty($_GET["pclr"]) ){
            $opts["theme_color"] = sanitize_hex_color(base64_decode(urldecode(trim($_GET["pclr"]))));
            $opts["preinvoice_theme_color"] = sanitize_hex_color(base64_decode(urldecode($_GET["pclr"])));
          }

          if ( isset($_GET["sclr"]) && !empty($_GET["sclr"]) ){
            $opts["theme_color2"] = sanitize_hex_color(base64_decode(urldecode($_GET["sclr"])));
            $opts["preinvoice_theme_color2"] = sanitize_hex_color(base64_decode(urldecode($_GET["sclr"])));
          }

          if ( isset($_GET["tclr"]) && !empty($_GET["tclr"]) ){
            $opts["theme_color3"] = sanitize_hex_color(base64_decode(urldecode($_GET["tclr"])));
            $opts["preinvoice_theme_color3"] = sanitize_hex_color(base64_decode(urldecode($_GET["tclr"])));
          }

          return $opts;
        }
        public function get_default_dynamic_params($order_id,$order)
        {
          $opts = array(
              "order_date_created"                     => $order->get_date_created() ? $this->fn->get_date($order->get_date_created()) : "",
              "order_date_modified"                    => $order->get_date_modified() ? $this->fn->get_date($order->get_date_modified()) : "",
              "order_date_completed"                   => $order->get_date_completed() ? $this->fn->get_date($order->get_date_completed()) : "",
              "order_date_current"                     => $this->fn->get_date(date_i18n("Y/m/d H:i",current_time("timestamp"))),
              "order_date_paid"                        => $order->get_date_paid() ? $this->fn->get_date($order->get_date_paid()) :"",
              "order_status"                           => wc_get_order_status_name($order->get_status()),
              "order_total"                            => $order->get_formatted_order_total(),
              "order_date_shipped"                     => !empty(get_post_meta($order_id,"_shipping_puiw_invoice_shipdate",true)) ? $this->fn->get_date( get_post_meta($order_id,"_shipping_puiw_invoice_shipdate",true),"Y/m/d",true ) : "",
              "order_date_shipped_raw"                 => get_post_meta($order_id,"_shipping_puiw_invoice_shipdate",true),
              "order_date_shipped_raw_shamsi"          => get_post_meta($order_id,"_shipping_puiw_invoice_shipdatefa",true),
              "store_name"                             => $this->fn->get_store_name(),
              "store_logo"                             => $this->fn->get_store_logo("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="),
              "store_website"                          => $this->fn->get_store_website(),
              "store_email"                            => $this->fn->get_store_email(),
              "store_phone"                            => $this->fn->get_store_phone(),
              "store_address"                          => $this->fn->get_store_address(),
              "wc_store_address"                       => $this->fn->get_wc_store_address(),
              "store_postcode"                         => $this->fn->get_store_postcode(),
              "store_national_id"                      => $this->fn->get_store_national_id(),
              "store_registration_number"              => $this->fn->get_store_registration_number(),
              "store_economical_number"                => $this->fn->get_store_economical_number(),
              "send_invoices_via_email"                => $this->fn->get_send_invoices_via_email(),
              "send_invoices_via_email_admin"          => $this->fn->get_send_invoices_via_email_admin(),
              "allow_users_use_invoices"               => $this->fn->get_allow_users_use_invoices(),
              "show_invoices_id_barcode"               => $this->fn->get_show_invoices_id_barcode(),
              "show_shippingslip_store"                => $this->fn->get_show_shippingslip_store(),
              "show_shippingslip_customer"             => $this->fn->get_show_shippingslip_customer(),
              "show_qr_code_id"                        => $this->fn->get_show_qr_code_id(),
              "postal_qr_code_label_for_store"         => $this->fn->get_postal_qr_code_label_for_store(),
              "postal_qr_code_label_for_customer"      => $this->fn->get_postal_qr_code_label_for_customer(),
              "date_shamsi"                            => $this->fn->get_date_shamsi(),
              "disable_wc_dashboard"                   => $this->fn->get_disable_wc_dashboard(),
              "allow_preorder_invoice"                 => $this->fn->get_allow_preorder_invoice(),
              "allow_preorder_emptycart"               => $this->fn->get_allow_preorder_emptycart(),
              "allow_pdf_customer"                     => $this->fn->get_allow_pdf_customer(),
              "allow_pdf_guest"                        => $this->fn->get_allow_pdf_guest(),
              "pdf_size"                               => $this->fn->get_pdf_size(),
              "pdf_orientation"                        => $this->fn->get_pdf_orientation(),
              "attach_pdf_invoices_to_mail"            => $this->fn->get_attach_pdf_invoices_to_mail(),
              "custom_css_style"                       => $this->fn->get_custom_css_style(),
              "custom_pdf_css_style"                   => $this->fn->get_pdf_css_style(),
              "inventory_css_style"                    => $this->fn->get_inventory_css_style(),
              "template"                               => $this->fn->get_template(),
              "theme_color"                            => $this->fn->get_theme_color(),
              "theme_color2"                           => $this->fn->get_theme_color2(),
              "theme_color3"                           => $this->fn->get_theme_color3(),
              "preinvoice_template"                    => $this->fn->get_preinvoice_template(),
              "preinvoice_theme_color"                 => $this->fn->get_preinvoice_theme_color(),
              "preinvoice_theme_color2"                => $this->fn->get_preinvoice_theme_color2(),
              "preinvoice_theme_color3"                => $this->fn->get_preinvoice_theme_color3(),
              "font_size"                              => $this->fn->get_font_size() . "px",
              "font_sizes"                             => $this->fn->get_font_size() - 4 . "px",
              "font_sizem"                             => $this->fn->get_font_size() - 2 . "px",
              "invoice_prefix"                         => $this->fn->get_invoice_prefix(),
              "invoice_suffix"                         => $this->fn->get_invoice_suffix(),
              "invoice_start"                          => $this->fn->get_invoice_start(),
              "signature"                              => $this->fn->get_signature(),
              "watermark"                              => $this->fn->get_watermark(),
              "watermark_blend"                        => $this->fn->get_watermark_blend(),
              "watermark_opacity"                      => $this->fn->get_watermark_opacity(),
              "watermark_opacity_10"                   => $this->fn->get_watermark_opacity()/100,
              "invoices_footer"                        => $this->fn->get_invoices_footer(),
              "show_custom_footer"                     => empty($this->fn->get_invoices_footer())?"no":"yes",
              "show_signature"                         => $this->fn->get_show_signatures(),
              "show_shelf_number_id"                   => $this->fn->get_show_shelf_number_id(),
              "show_product_sku_inventory"             => $this->fn->get_show_product_sku_inventory(),
              "show_product_sku2_inventory"            => $this->fn->get_show_product_sku2_inventory(),
              "show_product_image_inventory"           => $this->fn->get_show_product_image_inventory(),
              "show_product_weight_in_inventory"       => $this->fn->get_show_product_weight_in_inventory(),
              "show_product_total_weight_in_inventory" => $this->fn->get_show_product_total_weight_in_inventory(),
              "show_product_dimensions_in_inventory"   => $this->fn->get_show_product_dimensions_in_inventory(),
              "show_product_quantity_in_inventory"     => $this->fn->get_show_product_quantity_in_inventory(),
              "show_product_note_in_inventory"         => $this->fn->get_show_product_note_in_inventory(),
              "price_inventory_report"                 => $this->fn->get_price_inventory_report(),
              "show_order_note_inventory"              => $this->fn->get_show_order_note_inventory(),
              "show_store_national_id"                 => $this->fn->get_show_store_national_id(),
              "show_store_registration_number"         => $this->fn->get_show_store_registration_number(),
              "show_store_economical_number"           => $this->fn->get_show_store_economical_number(),
              "show_customer_address"                  => $this->fn->get_show_customer_address(),
              "show_customer_phone"                    => $this->fn->get_show_customer_phone(),
              "show_customer_email"                    => $this->fn->get_show_customer_email(),
              "show_order_date"                        => $this->fn->get_show_order_date(),
              "show_payment_method"                    => $this->fn->get_show_payment_method(),
              "show_shipping_method"                   => $this->fn->get_show_shipping_method(),
              "show_shipping_address"                  => $this->fn->get_show_shipping_address(),
              "address_display_method"                 => $this->fn->get_address_display_method(),
              "show_transaction_ref_id"                => $this->fn->get_show_transaction_ref_id(),
              "show_paid_date"                         => $this->fn->get_show_paid_date(),
              "show_purchase_complete_date"            => $this->fn->get_show_purchase_complete_date(),
              "show_shipping_date"                     => $this->fn->get_show_shipping_date(),
              "show_order_status"                      => $this->fn->get_show_order_status(),
              "show_product_image"                     => $this->fn->get_show_product_image(),
              "show_product_purchase_note"             => $this->fn->get_show_product_purchase_note(),
              "show_order_items"                       => $this->fn->get_show_order_items(),
              "show_order_total"                       => $this->fn->get_show_order_total(),
              "show_order_note"                        => $this->fn->get_show_order_note(),
              "show_user_uin"                          => $this->fn->get_show_user_uin(),
              "show_shipping_ref_id"                   => $this->fn->get_show_shipping_ref_id(),
              "show_price_template"                    => $this->fn->get_show_price_template(),
              "show_tax_display"                       => $this->fn->get_show_tax_display(),
              "show_product_weight"                    => $this->fn->get_show_product_weight(),
              "show_product_dimensions"                => $this->fn->get_show_product_dimensions(),
              "show_discount_precent"                  => $this->fn->get_show_discount_precent(),
              "show_discount_calc"                     => $this->fn->get_show_discount_calc(),
              "show_discount_display"                  => $this->fn->get_show_discount_display(),
              "show_product_tax"                       => $this->fn->get_show_product_tax(),
              "show_product_sku"                       => $this->fn->get_show_product_sku(),
              "show_product_sku2"                      => $this->fn->get_show_product_sku2(),
              "trnslt__print"                          => __("Print", $this->td),
              "trnslt__seller"                         => __("Seller", $this->td),
              "trnslt__buyer"                          => __("Buyer", $this->td),
              "trnslt__dates"                          => __("Extras", $this->td),
              "show_shipping_ref_id_colspan"           => 1,
              "invoice_final_prices_pre_colspan"       => 7,
              "product_description_colspan"            => 4,
              "product_nettotal_colspan"               => 1,
              "invoice_final_prices_colspan"           => 5,
              "invoice_final_row_colspan"              => 14,
          );
          $use_billing = $opts["show_shipping_address"];

          $opts["invoice_id"]                 = apply_filters("puiw_printinvoice_getinvoice_id",                $opts["invoice_prefix"] . ($opts["invoice_start"]+$order->get_id()) . $opts["invoice_suffix"], $opts, $order);
          $opts["invoice_id_en"]              = apply_filters("puiw_printinvoice_getinvoice_id_en",             $opts["invoice_prefix"] . ($opts["invoice_start"]+$order->get_id()) . $opts["invoice_suffix"], $opts, $order);
          $opts["invoice_id_nm"]              = apply_filters("puiw_printinvoice_getinvoice_id_raw",            $order->get_id(), $opts, $order);
          $opts["invoice_title"]              = apply_filters("puiw_printinvoice_getinvoice_title",             sprintf($this->fn->get_invoice_title(__("Invoice %s", $this->td)), $opts["invoice_id"]), $opts, $order);
          $opts["order_payment_method"]       = apply_filters("puiw_printinvoice_getinvoice_payment_method",    $order->get_payment_method_title(), $opts, $order);
          $opts["order_shipping_method"]      = apply_filters("puiw_printinvoice_getinvoice_shipping_method",   $order->get_shipping_method(), $opts, $order);
          $opts["customer_email"]             = apply_filters("puiw_printinvoice_getcustomer_email",            $order->get_billing_email(), $opts, $order);
          $opts["customer_phone"]             = apply_filters("puiw_printinvoice_getcustomer_phone",            $order->get_billing_phone(), $opts, $order);
          $opts["customer_fname"]             = apply_filters("puiw_printinvoice_getcustomer_firstname",        ($use_billing == "billing") ? $order->get_billing_first_name() :  $order->get_shipping_first_name(), $opts, $order, $use_billing);
          $opts["customer_lname"]             = apply_filters("puiw_printinvoice_getcustomer_lastname",         ($use_billing == "billing") ? $order->get_billing_last_name() :   $order->get_shipping_last_name(), $opts, $order, $use_billing);
          $opts["customer_fullname"]          = apply_filters("puiw_printinvoice_getcustomer_fullname",         ($use_billing == "billing") ? "{$order->get_billing_first_name()} {$order->get_billing_last_name()}" : "{$order->get_shipping_first_name()} {$order->get_shipping_last_name()}", $opts, $order, $use_billing);
          $opts["customer_company"]           = apply_filters("puiw_printinvoice_getcustomer_company",          ($use_billing == "billing") ? $order->get_billing_company() :     $order->get_shipping_company(), $opts, $order, $use_billing);
          $opts["customer_country"]           = apply_filters("puiw_printinvoice_getcustomer_country",          ($use_billing == "billing") ? ($order->get_billing_country() ? $order->get_billing_country() : "") : ($order->get_shipping_country() ? $order->get_shipping_country() : ""), $opts, $order, $use_billing);
          $opts["customer_state"]             = apply_filters("puiw_printinvoice_getcustomer_state",            ($use_billing == "billing") ? ($order->get_billing_state() ? $order->get_billing_state() : "") : ($order->get_shipping_state() ? $order->get_shipping_state() : ""), $opts, $order, $use_billing);
          $opts["customer_city"]              = apply_filters("puiw_printinvoice_getcustomer_city",             ($use_billing == "billing") ? ($order->get_billing_city() ? $order->get_billing_city() : "") : ($order->get_shipping_city() ? $order->get_shipping_city() : ""), $opts, $order, $use_billing);
          $opts["customer_address_1"]         = apply_filters("puiw_printinvoice_getcustomer_address_1",        ($use_billing == "billing") ? $order->get_billing_address_1() :   $order->get_shipping_address_1(), $opts, $order, $use_billing);
          $opts["customer_address_2"]         = apply_filters("puiw_printinvoice_getcustomer_address_2",        ($use_billing == "billing") ? $order->get_billing_address_2() :   $order->get_shipping_address_2(), $opts, $order, $use_billing);
          $opts["customer_postcode"]          = apply_filters("puiw_printinvoice_getcustomer_postcode",         ($use_billing == "billing") ? $order->get_billing_postcode() :    $order->get_shipping_postcode(), $opts, $order, $use_billing);
          $opts["customer_signature"]         = apply_filters("puiw_printinvoice_getinvoicecustomer_signature", get_post_meta($order->get_id(), '_shipping_puiw_customer_signature', true), $opts, $order);
          $opts["order_transaction_ref_id"]   = apply_filters("puiw_printinvoice_getinvoice_shipping_method",   get_post_meta($order->get_id(), '_transaction_id', true), $opts, $order);
          $opts["customer_uin"]               = apply_filters("puiw_printinvoice_getcustomer_uin",              get_post_meta($order->get_id(), 'puiw_billing_uin', true), $opts, $order);
          $opts["invoice_qrcode"]             = apply_filters("puiw_printinvoice_getinvoice_qrdata",            add_query_arg( "invoice", $order->get_id(),home_url()), $opts, $order);
          $opts["invoice_qrcode"]             = wp_strip_all_tags( $opts["invoice_qrcode"], true );

          $get_base_countries = WC()->countries->__get('countries');
          $get_base_states = WC()->countries->get_states($opts["customer_country"]);

          $opts["customer_address"]           = str_replace(
              apply_filters("puiw_printinvoice_address_template",
                  array(
                  "[first_name]",
                  "[last_name]",
                  "[company]",
                  "[country]",
                  "[province]",
                  "[city]",
                  "[address1]",
                  "[address2]",
                  "[po_box]",
                  "[email]",
                  "[phone]",
                  "[uin]"
                  ),  $opts, $order
              ),
              apply_filters("puiw_printinvoice_address_template_replace",
                  array(
                  $opts["customer_fname"],
                  $opts["customer_lname"],
                  $opts["customer_company"],
                  $get_base_countries[$opts["customer_country"]] ? $get_base_countries[$opts["customer_country"]] : $opts["customer_country"],
                  $get_base_states[$opts["customer_state"]] ? $get_base_states[$opts["customer_state"]] : $opts["customer_state"],
                  $opts["customer_city"],
                  $opts["customer_address_1"],
                  $opts["customer_address_2"],
                  $opts["customer_postcode"],
                  $opts["customer_email"],
                  $opts["customer_phone"],
                  $opts["customer_uin"]
                  ),  $opts, $order
              ),
              $this->fn->get_address_display_method()
          );
          // $opts["customer_address"]        = ($use_billing == "billing") ? $order->get_formatted_billing_address() : $order->get_formatted_shipping_address();
          $opts["invoice_track_id"]           = get_post_meta($order->get_id(), 'puiw_invoice_track_id', true);
          $opts["invoice_track_id_en"]        = $opts["invoice_track_id"] ? $opts["invoice_track_id"] : "0000000000000000";
          $opts["invoice_final_price"]        = $order->get_formatted_order_total();
          $opts["invoice_final_prices"]       = $this->get_order_final_prices($order);
          $opts["invoice_final_prices_pdf"]   = $this->get_order_final_prices_pdf($order);
          $opts["invoice_total_qty"]          = "0";
          $opts["invoice_total_weight"]       = "0";
          $opts["invoice_products_list"]      = "";
          $opts["home_url"]                   = home_url();

          if (empty(trim($opts["customer_signature"]))){
            $opts["customer_signature_css"] = "display: none !important; width:0; height:0;";
            $opts["customer_signature"] = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
          }
          if (empty(trim($opts["signature"]))){
            $opts["signature_css"] = "display: none !important; width:0; height:0;";
            $opts["signature"] = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
          }

          global $PeproUltimateInvoice;
          $generator                         = $PeproUltimateInvoice->barcode;
          $defaultemptyimg                   = 'data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQAAAAClSfIQAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAd2KE6QAAAAHdElNRQfmCQMPAQF2LNlKAAAADklEQVQI12P4f4ABNwIAB1IRd+bI0OMAAAAASUVORK5CYII=';
          $opts["invoice_barcode"]           = 'data:image/jpeg;base64,' . base64_encode($generator->getBarcode($opts["invoice_id_en"], $generator::TYPE_CODE_128));
          $opts["invoice_track_barcode"]     = empty($opts["invoice_track_id_en"])  ? $defaultemptyimg : ('data:image/jpeg;base64,' . base64_encode($generator->getBarcode($opts["invoice_track_id_en"], $generator::TYPE_CODE_128)));
          $opts["customer_postcode_barcode"] = empty($opts["customer_postcode"])    ? $defaultemptyimg : ('data:image/jpeg;base64,' . base64_encode($generator->getBarcode($opts["customer_postcode"], $generator::TYPE_CODE_128)));
          $opts["store_postcode_barcode"]    = empty($opts["store_postcode"])       ? $defaultemptyimg : ('data:image/jpeg;base64,' . base64_encode($generator->getBarcode($opts["store_postcode"], $generator::TYPE_CODE_128)));

          return apply_filters( "puiw_get_default_dynamic_params", $opts, $order);
        }
        public function get_preserve_english_numbers($opt, $order)
        {
          return $keepOriginalENnumbers = apply_filters("puiw_printinvoice_preserve_english_numbers",
            array(
              "invoice_id_en",
              "invoice_track_id_en",
              "invoice_products_list",
              "customer_postcode",
              "invoice_final_price",
              "store_postcode",
              "customer_postcode_barcode",
              "store_postcode_barcode",
              "invoice_id_nm",
              "product_description_colspan",
              "product_nettotal_colspan",
              "invoice_final_prices_pre_colspan",
              "invoice_final_prices_colspan",
              "invoice_final_row_colspan",
              "invoice_final_prices",
              "invoice_final_prices_pdf",
              "store_logo",
              "order_total",
              "invoice_qrcode",
              "invoice_barcode",
              "invoice_track_barcode",
              "store_website",
              "show_invoices_id_barcode_colspan",
              "custom_css_style",
              "custom_pdf_css_style",
              "inventory_css_style",
              "store_email",
              "base_price",
              "discount",
              "nettotal",
              "tax",
              "sku",
              "font_sizes",
              "font_sizem",
              "font_size",
              "signature",
              "customer_signature",
              "watermark",
              "watermark_opacity",
              "watermark_opacity_10",
              "theme_color",
              "theme_color2",
              "theme_color3",
              "show_shipping_ref_id_colspan",
              "extra_classes",
              "img",
            ),
            $opt,
            $order
          );
        }
        public function get_preserve_html_tags($opt, $order)
        {
          return apply_filters("puiw_printinvoice_preserve_html_tags",
            array(
              "invoice_final_prices",
              "invoice_final_prices_pdf",
              "invoice_products_list",
              "invoices_footer",
              "base_price",
              "invoice_notes",
              "invoice_note_customer",
              "invoice_note_shopmngr",
              "order_total",
              "custom_css_style",
              "custom_pdf_css_style",
              "inventory_css_style",
            ),
            $opt,
            $order
          );
        }
        public function has_access($type="HTML", $order=false)
        {

          if ( has_filter("puiw_printinvoice_check_user_has_access")){
            return apply_filters("puiw_printinvoice_check_user_has_access", false, $type, $order);
          }

          // Allow Customer/Users view invoices
          $allow_users_view_invoices = $this->fn->get_allow_users_have_invoices();
          // Invoice Output for Customers
          $access_customer = $this->fn->get_allow_pdf_customer();

          // Allow Guest Users view invoices
          $allow_guest_view_invoices = $this->fn->get_allow_guest_users_view_invoices();
          // Invoice Output for Guest Users
          $access_guest = $this->fn->get_allow_pdf_guest();

          // USER IS LOGGED IN
          if (is_user_logged_in()){

            $user = wp_get_current_user();
            $user_id = get_current_user_id();
            $order = wc_get_order( $order );
            if (!$order) return false;
            // force allow admins
            if ( in_array( "administrator", (array) $user->roles )  || in_array( "shop_manager", (array) $user->roles ) ){ return true; }
            // prevent users to see others' invoices
            if ( $user_id !== $order->get_user_id() ){
              return false;
            }
            // now if user is viewing his order, let's show him
            else{
              // Allow Customer/Users view invoices is NOT CHECKED
              if ("yes" !== $allow_users_view_invoices ){
                return false;
              }
              // Allow Customer/Users view invoices IS CHECKED
              // Request is PDF invoice
              if ("PDF" == $type){
                // Invoice Output for Customers includes pdf or both
                if ( "pdf" == $access_customer  || "both" == $access_customer ){
                  return true;
                }
              }
              // Request is HTML invoice
              else{
                // Invoice Output for Customers includes html or both
                if ( "html" == $access_customer  || "both" == $access_customer ){
                  return true;
                }
              }
              // Invoice Output for Customers is not sufficient
              return false;
            }
          }
          // USER IS GUEST AND NOT LOGGED IN
          else{
            // Allow Guests view invoices IS CHECKED
            if ("yes" == $allow_guest_view_invoices ){
              // Request is PDF invoice
              if ("PDF" == $type){
                // Invoice Output for Guests includes pdf or both
                if ( "pdf" == $access_guest  || "both" == $access_guest ){
                  return true;
                }
              }
              // Request is HTML invoice
              else{
                // Invoice Output for Guests includes html or both
                if ( "html" == $access_guest  || "both" == $access_guest ){
                  return true;
                }
              }
              // Invoice Output for Guests is not sufficient
              return false;
            }
            // Allow Guests view invoices is NOT CHECKED
            else{
              return false;
            }
          }
          // in case of fatal error, return 403
          return false;
        }
        public function create_html($order_id=0, $MODE="HTML",$part="",$email_printout="",$skipAuth=false)
        {
          if (!$this->CheckPDFRequirementsHTML()){ $this->CheckPDFRequirementsHTML(true); }
          if (!$order_id || empty(trim($order_id)) || !is_numeric(trim($order_id))) {return __('Incorrect data!', $this->td);}
          (int) $order_id = trim($order_id);
          $order = wc_get_order($order_id);
          if (!$order) {return __('Incorrect Order!', $this->td);}
          if (!$skipAuth){
            if ("HTML" == $MODE && !$this->has_access("HTML",$order)){ global $PeproUltimateInvoice; $PeproUltimateInvoice->die("printClass_create_html auth_check", __("Err 403 - Access Denied", $this->td), $PeproUltimateInvoice->Unauthorized_Access); }
            if ("PDF" == $MODE && !$this->has_access("PDF",$order)){ global $PeproUltimateInvoice; $PeproUltimateInvoice->die("printClass_create_html_pdf auth_check", __("Err 403 - Access Denied", $this->td), $PeproUltimateInvoice->Unauthorized_Access); }
          }
          ob_start();
          $opts = $this->get_default_dynamic_params($order_id,$order);
          if ("PDF" == $MODE) {
            $opts["invoice_final_prices"] = $this->get_order_final_prices_pdf($order);
          }
          $opt = apply_filters("puiw_printinvoice_create_html_options", $opts, $order);
          $opt["CURENT_DIR_URL"] = apply_filters( "puiw_get_template_dir_url", plugin_dir_url($opt["template"]) ,$opt["template"] ,$order);
          $keepOriginalHTMLtags  = $this->get_preserve_html_tags($opt, $order);
          $keepOriginalENnumbers = $this->get_preserve_english_numbers($opt, $order);
          do_action("puiw_printinvoice_before_create_html", $opt, $opts, $order);
          $main_css_style_inline = "";
          $order_note_a = apply_filters( "puiw_printinvoice_order_note_customer", "<strong>".__("Note provided by Customer",$this->td)."</strong><br><div>" . $this->fn->get_order_note($order,"a")."</div>", $this->fn->get_order_note($order,"a"), $order, $opt);
          $order_note_b = apply_filters( "puiw_printinvoice_order_note_shopmngr", "<strong>".__("Note provided by Shop manager",$this->td)."</strong><br><div>" . $this->fn->get_order_note($order,"b")."</div>", $this->fn->get_order_note($order,"b"), $order, $opt);
          switch ($opt["show_order_note"]) {
            // hide_note_from_invoice, note_provided_by_customer, note_provided_by_shop_manager, note_provided_by_both
            case 'note_provided_by_customer':
              $notes = "<td>$order_note_a</td>";
              $opt["show_order_note"] = "yes";
              break;
            case 'note_provided_by_shop_manager':
              $notes = "<td>$order_note_b</td>";
              $opt["show_order_note"] = "yes";
              break;
            case 'note_provided_by_both':
              $notes = "<td>$order_note_b</td>
                        <td>$order_note_a</td>";
              $opt["show_order_note"] = "yes";
              break;
            default:
              $notes = "";
              $opt["show_order_note"] = "no";
              break;
          }
          foreach ($opt as $key => $value) {
            if (substr($key,0,5) == "show_" && $value !== "yes"){
              $main_css_style_inline .= "[if~='$key']{display:none !important; visibility: hidden !important;}" . PHP_EOL;
              $main_css_style_inline .= ".$key{width: 0cm; display:none !important; visibility: hidden !important;}" . PHP_EOL;
              if ("PDF" == $MODE){
                $opt["{$key}_hide_css"] = 'width:0 !important; margin: 0 !important; padding: 0 !important; font-size: 0 !important; display: none !important; visibility: hidden !important;';
                $opt["{$key}_display_none"] = 'display: none;';
                $opt["{$key}_hc"] = 'width:0 !important; margin: 0 !important; padding: 0 !important; font-size: 0 !important; display: none !important; visibility: hidden !important;';
                $opt["{$key}_dn"] = 'display: none;';
              }
            }

            if ((substr($key,0,5) == "show_") && ($value == "yes") && ("PDF" == $MODE)){
              $opt["{$key}_hide_css"] = '';
              $opt["{$key}_display_none"] = '';
              $opt["{$key}_hc"] = '';
              $opt["{$key}_dn"] = '';
            }
          }
          if (trim($opt["watermark"]) == ""){
            // $main_css_style_inline .= '[if~="watermark"]{display:none !important; visibility: hidden !important;}';
          }
          if ($opt["show_invoices_id_barcode"] !== "yes" || $email_printout){
            $opt["show_invoices_id_barcode_colspan"] = 2 ;
          }
          if ($opt["show_shipping_ref_id"] !== "yes" || $email_printout){
            $opt["show_shipping_ref_id_colspan"] = 2;
          }
          if ($opt["show_product_weight"] !== "yes"){
            if ("PDF" !== $MODE){$opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1;}
          }
          if ($opt["show_product_dimensions"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
              $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] -1 ;
            }
          }
          if ($opt["show_product_sku"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
              $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] -1 ;
            }
          }
          if ($opt["show_product_image"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
              $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] -1 ;
            }
          }
          if ($opt["show_product_image"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
              $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] -1 ;
            }
          }
          if ($opt["show_discount_precent"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["product_nettotal_colspan"] = $opt["product_nettotal_colspan"] + 1;
              // $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] + 1;
              // $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] +1 ;
            }
          }
          if ($opt["show_product_tax"] !== "yes"){
            if ("PDF" !== $MODE){
              $opt["product_nettotal_colspan"] = $opt["product_nettotal_colspan"] + 1;
              // $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] + 1;
              // $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] +1 ;
            }
          }
          $templateDirpath = apply_filters( "puiw_get_template_dir_path", $opt["template"], $order);
          $opt["invoice_note_customer"] = $order_note_a;
          $opt["invoice_note_shopmngr"] = $order_note_b;
          $opt["invoice_notes"] = $notes;
          if ("PDF_EXTRA_STYLE" == $MODE) { return $main_css_style_inline.$opts["custom_pdf_css_style"];}
          if ("PDF" == $MODE) {
              $template                     = file_get_contents("$templateDirpath/template.pdf.tpl");
              if(!empty($part)){ $template  = file_get_contents("$templateDirpath/template.pdf.{$part}.tpl"); }
              $product_row_RAW              = file_get_contents("$templateDirpath/template.pdf.row.tpl");
          }
          else{
              $extrainvoiceheaddata   = '';
              $main_css_style         = file_get_contents("$templateDirpath/style.css");
              if ($email_printout){   $main_css_style = file_get_contents("$templateDirpath/style.email.css"); }
              $main_css_style         = $main_css_style_inline . $main_css_style;
              $body_content           = '';
              if (!$email_printout)   {
                $body_content           = '<p style="text-align:center;">';
                if ($skipAuth){
                  $body_content .= '<a class="print-button" href="javascript:;" onclick="window.print();return false;" >'.__("PRINT",$this->td).'</a>';
                  $body_content .= '<a class="print-button" href="javascript:;" onclick="window.open(window.location.href.replace(\'?invoice=\',\'?invoice-pdf=\'))" >'.__("GET PDF",$this->td).'</a>';
                }else{
                  if ($this->has_access("HTML",$order)) { $body_content .= '<a class="print-button" href="javascript:;" onclick="window.print();return false;">'.__("PRINT",$this->td).'</a>'; }
                  if ($this->has_access("PDF",$order))  { $body_content .= '<a class="print-button" href="javascript:;" onclick="window.open(window.location.href.replace(\'?invoice=\',\'?invoice-pdf=\'))" >'.__("GET PDF",$this->td).'</a>'; }
                }
                $body_content           .= '</p>';
              }
              $body_content           .= file_get_contents("$templateDirpath/template.tpl");
              $invoicehtmltitle       = "{{{invoice_title}}} | {{{store_name}}}";
              $body_content           = apply_filters( "puiw_printinvoice_HTML_body", $body_content, $order_id);
              $extrainvoiceheaddata   = apply_filters( "puiw_printinvoice_HTML_extrahead", $extrainvoiceheaddata, $order_id);
              $invoicehtmltitle       = apply_filters( "puiw_printinvoice_HTML_title", $invoicehtmltitle, $order_id);
              $main_css_style         = apply_filters( "puiw_printinvoice_HTML_style", $main_css_style,$main_css_style_inline, $order_id);
              $product_row_RAW        = file_get_contents("$templateDirpath/template.row.tpl");
              $template               = "<!DOCTYPE html><html lang=\"fa\" dir=\"ltr\"><head><title>$invoicehtmltitle</title>$extrainvoiceheaddata<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><style type='text/css'>{$main_css_style}{{{custom_css_style}}}</style></head>$body_content</html>";
          }

          $n=0;$total_weight = 0;
          foreach ( apply_filters( "puiw_order_items", $order->get_items(), $order) as $item_id => $item ) {
              $n+=1;
              $product_row  = ($product_row_RAW);
              $product_id   = $item->get_product_id();
              $variation_id = $item->get_variation_id();
              $somemeta     = $item->get_meta('_whatever', true);
              $product      = $item->get_product();
              if (!$product){continue;}
              $type                = $item->get_type();
              $active_price        = $product->get_price(); // The product active raw price
              $sale_price          = (float)$product->get_sale_price(); // The product raw sale price
              $regular_price       = (float)$product->get_regular_price(); // The product raw regular price
              $prev_regular_price  = (float)$item->get_meta('_puiw_regular', true);
              $prev_sale_price     = (float)$item->get_meta('_puiw_sale', true);
              $prev_price_html     = $item->get_meta('_puiw_html', true);
              $name                = apply_filters( "puiw_invoice_item_get_name",              $item->get_name(), $product, $item, $order);
              $extra_classes       = apply_filters( "puiw_invoice_item_extra_classes",         [], $product, $item_id, $item, $order, $n);
              $quantity            = apply_filters( "puiw_invoice_item_get_quantity",          $item->get_quantity(), $product, $item, $order);
              $subtotal            = apply_filters( "puiw_invoice_item_get_subtotal",          wc_price($item->get_subtotal()), $product, $item, $order);
              $tax                 = apply_filters( "puiw_invoice_item_get_subtotal_tax",      wc_price($item->get_subtotal_tax()), $product, $item, $order);
              $net_total           = apply_filters( "puiw_invoice_item_get_total",             wc_price($item->get_total()), $product, $item, $order);
              $tax_total           = apply_filters( "puiw_invoice_item_get_total_tax",         wc_price($item->get_total_tax()), $product, $item, $order);
              $total               = apply_filters( "puiw_invoice_item_get_total_tax_inc",     wc_price($item->get_total() + $item->get_total_tax()), $product, $item, $order);
              $taxclass            = apply_filters( "puiw_invoice_item_get_tax_class",         $item->get_tax_class(), $product, $item, $order);
              $taxstat             = apply_filters( "puiw_invoice_item_get_tax_status",        $item->get_tax_status(), $product, $item, $order);
              $allmeta             = apply_filters( "puiw_invoice_item_get_meta_data",         $item->get_meta_data(), $product, $item, $order);
              $description         = apply_filters( "puiw_invoice_item_get_purchase_note",     $product->get_purchase_note(), $product, $item, $order);
              $description        .= $this->get_item_meta($item_id, $item, $product);
              $weight_raw          = apply_filters( "puiw_invoice_item_get_product_weight_raw",$product->get_weight() , $product, $item, $order);
              $weight              = apply_filters( "puiw_invoice_item_get_product_weight",    $this->fn->get_format_weight($weight_raw), $product, $item, $order);
              $dimension           = apply_filters( "puiw_invoice_item_get_product_dimension", $this->fn->get_product_dimension($item->get_product_id()), $product, $item, $order);
              $sku                 = $product->get_sku();

              if ($opt["show_product_sku2"] == "yes"){
                $sku = empty($sku) || !$sku ? "#$product_id" : $sku;
              }
              $product_weight = $weight_raw ? $weight_raw : 0;
              if ($product_weight) {
                $total_weight += floatval( $product_weight * $quantity );
                $opt["invoice_total_weight"] = apply_filters( "puiw_printinvoice_calculate_invoice_total_weight", $this->fn->get_format_weight($total_weight), $total_weight, $product_weight, $quantity, $product, $item, $order);
              }
              $opt["invoice_total_qty"] = (int) $opt["invoice_total_qty"] + $quantity;

              // Line item Price Display
              switch ($opt["show_price_template"]) {

                //Show WC_Order price (as shown in order details screen)
                case 'show_wc_price':
                  $base_price = wc_price($order->get_item_subtotal( $item, false, true ), array( 'currency' => $order->get_currency() ) );
                break;
                //Show Current-live regular price
                case 'show_only_regular_price':
                  $base_price = wc_price($product->get_regular_price(), array( 'currency' => $order->get_currency() ));
                break;
                //Show Current-live sale price
                case 'show_only_sale_price':
                  $base_price = wc_price($product->get_sale_price(), array( 'currency' => $order->get_currency() ));
                break;
                //Show Current-live regular/sale price
                case 'show_both_regular_and_sale_price':
                  $base_price = $product->get_price_html();
                break;
                //Show Saved Line-item regular price
                case 'show_saved_regular_price':
                  $base_price = wc_price($prev_regular_price, array( 'currency' => $order->get_currency() ));
                break;
                //Show Saved Line-item sale price
                case 'show_saved_sale_price':
                  $base_price = wc_price($prev_sale_price, array( 'currency' => $order->get_currency() ));
                break;
                //Show Saved Line-item sale/regular price
                case 'show_saved_regular_and_sale_price':
                  $base_price = $prev_price_html;
                break;
                default:
                  $base_price = wc_price($order->get_item_subtotal( $item, false, true ), array( 'currency' => $order->get_currency() ) );
                break;
              }

              $discount_display = "";
              $refunded_dispaly = "";
              $refunded         = -1 * $order->get_total_refunded_for_item( $item_id );
              if ( $refunded ) {
                $refunded_dispaly = '<small class="refunded">' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
              }
              $discount_amount = wc_price( 00 , array( 'currency' => $order->get_currency() ) );
              $discount_precent = sprintf("%'02.1f%%", 0);

              // Line item Discount Calculation
              switch ($opt["show_discount_calc"]) {
                // Based on WC_Order (as shown in order details screen)
                case 'wcorder':
                  if ( $item->get_subtotal() !== $item->get_total() ) {
                    $discount_amount  = $item->get_subtotal() - $item->get_total() > 0 ? wc_price( wc_format_decimal( $item->get_subtotal() - $item->get_total(), '' ), array( 'currency' => $order->get_currency() ) ) : "";
                    $percentage       = $this->calc_precentage((float)$item->get_subtotal(), (float)$item->get_total());
                    $discount_precent = sprintf("%'02.1f%%", $percentage);
                  }
                break;
                  // Based on Product's current-live sale/regular price
                case 'liveprice':
                  if ( $sale_price > 0 && $sale_price < $regular_price ) {
                    $discount_amount  = (($regular_price - $sale_price) > 0) ? wc_price( wc_format_decimal( $regular_price - $sale_price, '' ), array( 'currency' => $order->get_currency() ) ) : "";
                    $percentage       = $this->calc_precentage($sale_price, $regular_price);
                    $discount_precent = $percentage > 0 ? sprintf("%'02.1f%%", $percentage) : "";
                  }else{
                    $discount_amount  = "";
                    $discount_precent = "";
                  }
                break;
                  // Based on Line-item saved sale/regular price
                case 'savepirce':
                if ( $prev_sale_price > 0 && $prev_sale_price < $prev_regular_price ) {
                  $discount_amount  = (($prev_regular_price - $prev_sale_price) > 0) ? wc_price( wc_format_decimal( $prev_regular_price - $prev_sale_price, '' ), array( 'currency' => $order->get_currency() ) ) : "";
                  $percentage       = $this->calc_precentage($prev_sale_price, $prev_regular_price);
                  $discount_precent = $percentage > 0 ? sprintf("%'02.1f%%", $percentage) : "";
                }else{
                  $discount_amount  = "";
                  $discount_precent = "";
                }
                break;
                  // Based on Discounted Line-item saved sale/regular price
                case 'advanced':
                  // in next releases, maybe
                break;
              }

              // Line item Discount Display
              switch ($opt["show_discount_display"]) {
                // Show discount value
                case 'value':
                  $discount_display = $discount_amount;
                break;
                // Show discount precentage
                case 'precnt':
                  $discount_display = $discount_precent;
                break;
                // Show discount precentage and value
                case 'both':
                default:
                  $discount_display = "<div>".(!empty($discount_precent) ? "($discount_precent)" : "")."</div><div>$discount_amount</div>";
                  break;
              }
              $discount_display = apply_filters( "puiw_invoice_item_get_product_discount", $discount_display, $discount_precent, $discount_amount, $opt["show_discount_calc"], $opt["show_discount_display"], $product, $item, $order);

              if (empty(trim($base_price))) {
                $base_price = wc_price($order->get_item_subtotal( $item, false, true ), array( 'currency' => $order->get_currency() ) );
              }

              $tax_formatted = $tax;
              $tax_formatted_amount = $tax;
              if ( wc_tax_enabled() ) {
                $order_taxes      = $order->get_taxes();
                $tax_classes      = \WC_Tax::get_tax_classes();
                $classes_options  = wc_get_product_tax_class_options();
                $show_tax_columns = count( $order_taxes ) === 1;
              }
              if ( ( $tax_data = $item->get_taxes() ) && wc_tax_enabled() ) {
                $tax_formatted = "";
                $tax_formatted_amount = "";
            		foreach ( $order_taxes as $tax_item ) {
                  $column_label   = ! empty( $tax_item['label'] ) ? $tax_item['label'] : __( 'Tax', 'woocommerce' );
            			$tax_item_id    = $tax_item->get_rate_id();
            			$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
                  $tax_formatted .= '<div class="line_tax"><small style="display: block;" class="tax-title">'.$column_label.'</small>'.(( '' !== $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ), array( 'currency' => $order->get_currency() ) ) : '&ndash;');
                  if ( $refunded = -1 * $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'fee' ) ) {
                    $tax_formatted .= '<small class="refunded">' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>';
                  }
                  $tax_formatted .= '</div>';

                  $tax_formatted_amount .= '<div class="line_tax">'.(( '' !== $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ), array( 'currency' => $order->get_currency() ) ) : '&ndash;');
                  if ( $refunded = -1 * $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'fee' ) ) {
                    $tax_formatted_amount .= '<small class="refunded">' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>';
                  }
                  $tax_formatted_amount .= '</div>';
            		}
            	}
              $tax_formatted = apply_filters( "puiw_printinvoice_create_html_lineitem_tax_formatted", $tax_formatted, $order, $item);
              switch ($opt["show_tax_display"]) {

                //Show taxes amount
                case "amount":
                $tax_formatted = $tax_formatted_amount;
                break;

                //Show line total tax amount
                case "onlytotal":
                $tax_formatted = $tax_total;
                break;

                //Show taxes label and amount
                case "labelamount":
                default:
                $tax_formatted = $tax_formatted;
                break;
              }

              if ($this->is_bundled_child($item_id)){
                $base_price = "";
                $subtotal = "";
                if ($this->_woosb_show_bundled_hierarchy == "yes"){
                  $n = $n-1;
                }
              }

              $totalweight = apply_filters( "puiw_printinvoice_create_html_total_weight", $this->fn->get_format_weight(floatval($product_weight*$quantity)), floatval($product_weight*$quantity), $product_weight, $quantity, $item_id, $item, $product_id, $order );
              $optm = array(
                "n"                           => $n,
                "img"                         => ("PDF" == $MODE) ? $product->get_image(array( 50, 50 )) : $product->get_image('shop_thumbnail'),
                "sku"                         => $sku,
                "title"                       => $name,
                "qty"                         => $quantity,
                "base_price"                  => $base_price,
                "description"                 => $description,
                "extra_classes"               => implode(" ", (array) $extra_classes),
                "discount"                    => $discount_display,
                "weight"                      => $weight_raw>0?$weight:"",
                "total_weight"                => $totalweight,
                "product_description_colspan" => $opt["product_description_colspan"],
                "product_nettotal_colspan"    => $opt["product_nettotal_colspan"],
                "dimension"                   => $dimension,
                "tax"                         => $tax_formatted,
                "nettotal"                    => $total,
                "shelf_number_id"             => get_post_meta( $product_id, "_shelf_number_id", true),
              );
              $optm = apply_filters( "puiw_printinvoice_create_html_item_row_metas", $optm, $item_id, $item, $product_id, $order );

              foreach ($optm as $key => $value) {
                if (!in_array($key, $keepOriginalENnumbers)) {
                  $value = $this->fn->parse_number($value);
                }
                $product_row = str_replace("{{{{$key}}}}", $value, $product_row);
              }
              $opt["invoice_products_list"] .= $product_row;
          }
          foreach ($opt as $key => $value) {
            if (!in_array($key, $keepOriginalENnumbers)) {
              $value = $this->fn->parse_number($value);
            }
            $value = apply_filters("puiw_printinvoice_create_html_options_{$key}_value", $value, $key, $order);
            if (!in_array($key, $keepOriginalHTMLtags)){
              $template = str_replace("{{{{$key}}}}", wp_strip_all_tags($value, 1), ($template));
            }
            else{
              $template = str_replace("{{{{$key}}}}", $value, $template);
            }
          }
          if(apply_filters("puiw_printinvoice_return_html_minfied", true, $template, $opt, $order)){
            $template = $this->minify_html($template);
          }

          do_action("puiw_printinvoice_after_create_html", $opt, $opts, $order);
          do_action("puiw_printinvoice_before_return_html", $opt, $opts, $order);
          echo apply_filters("puiw_printinvoice_return_html", $template, $opt, $opts, $order);
          do_action("puiw_printinvoice_after_return_html", $opt, $opts, $order);
          $html_output = ob_get_contents();
          ob_end_clean();
          return $html_output;
        }
        public function calc_precentage($offprice=0, $realprice=0)
        {
          // 100 - (newPrice / wasPrice) * 100
          return round(100 - (($offprice / $realprice) * 100), 5);
        }
        public function create_pdf($order_id=0, $force_download = false, $MODE="I", $showerror=true)
        {
          // 'D': download the PDF file
          // 'I': serves in-line to the browser
          // 'S': returns the PDF document as a string
          // 'F': save as file $file_out
          if (!$order_id || empty(trim($order_id)) || !is_numeric(trim($order_id))){ return __('Incorrect data!', $this->td); }
          (int) $order_id = trim($order_id);
          $order = wc_get_order($order_id);
          if (!$order) {return false;}
          $skipAuth = true;
          if ("S" !== $MODE){
            $skipAuth = false;
            if (!$this->has_access("PDF",$order)){ global $PeproUltimateInvoice; $PeproUltimateInvoice->die("printClass_create_pdf auth_check", __("Err 403 - Access Denied", $this->td), $PeproUltimateInvoice->Unauthorized_Access); }
          }
          if (!$this->CheckPDFRequirements()){ $this->CheckPDFRequirements($showerror); }
          global $PeproUltimateInvoice;
          // add_filter("woocommerce_price_format", function () {return '%2$s %1$s';}, 10000, 2); // you should change it from wc setting
          require_once PEPROULTIMATEINVOICE_DIR . '/include/vendor/autoload.php';
          $class                  = "pepro-one-page-purchase---invoice-simple";
          $class                 .= is_rtl() ? "rtl" : "";
          $dire                   = is_rtl() ? 'rtl' : 'ltr';
          $texe                   = is_rtl() ? 'right' : 'left';
          $defaultConfig          = (new \Mpdf\Config\ConfigVariables())->getDefaults();
          $fontDirs               = $defaultConfig['fontDir'];
          $defaultFontConfig      = (new \Mpdf\Config\FontVariables())->getDefaults();
          $fontData               = $defaultFontConfig['fontdata'];

          $template               = $this->fn->get_template();
          $templateDirpath        = apply_filters( "puiw_get_template_dir_path", $template, $order);


          $contents               = file_get_contents("$templateDirpath/default.cfg");

          $template_pdf_setting   = $this->parseTemplate($contents);
          /* if we had an error, don't let script stop !*/
          $get_allow_pdf_customer = $this->fn->get_allow_pdf_customer();
          $get_pdf_size           = $this->fn->get_pdf_size();
          $get_pdf_orientation    = $this->fn->get_pdf_orientation();

          $_fontData = $fontData + [
            'dejavu' => [
              'R' => 'DejaVuSans.ttf',
              'B' => 'DejaVuSans-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iranyekanen' => [
              'R' => 'IRANYekanRegular.ttf',
              'B' => 'IRANYekanBold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iranyekanfa' => [
              'R' => 'IRANYekanRegular(FaNum).ttf',
              'B' => 'IRANYekanBold(FaNum).ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iransans' => [
              'R' => 'IRANSans.ttf',
              'B' => 'IRANSans_Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iransansfa' => [
              'R' => 'IRANSans(FaNum).ttf',
              'B' => 'IRANSans(FaNum)_Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'danaen' => [
              'R' => 'Dana-Regular.ttf',
              'B' => 'Dana-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'danafa' => [
              'R' => 'Dana-FaNum-Regular.ttf',
              'B' => 'Dana-FaNum-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
          ];


          if ("L" == $get_pdf_orientation){$get_pdf_size = "$get_pdf_size-L";}
          // https://mpdf.github.io/paging/page-size-orientation.html
          $get_pdf_size = apply_filters("puiw_generate_pdf_page_size", $get_pdf_size, $order_id, $order, "PDF");

          $daynamic_params = $this->get_default_dynamic_params($order_id, $order);
          
          error_reporting(0);
          @ini_set("display_errors", 0);
          @ini_set("max_execution_time", "300");
          @ini_set("pcre.backtrack_limit", PHP_INT_MAX);
          @ini_set('memory_limit', '2048M');

          try {
            $mpdf = new \Mpdf\Mpdf(apply_filters("puiw_create_pdf_Mpdf_options", array(
              "fontDir"                => array_merge($fontDirs, [plugin_dir_path(__FILE__)]),
              "mode"                   => "utf-8",
              "fontdata"               => $_fontData,
              "default_font"           => $this->fn->get_pdf_font(),
              "format"                 => $get_pdf_size, // A4-L
              "margin_right"           => $template_pdf_setting["pdf_margin_right"],
              "margin_left"            => $template_pdf_setting["pdf_margin_left"],
              "margin_top"             => $template_pdf_setting["pdf_margin_top"],
              "margin_bottom"          => $template_pdf_setting["pdf_margin_bottom"],
              "margin_header"          => $template_pdf_setting["pdf_margin_header"],
              "margin_footer"          => $template_pdf_setting["pdf_margin_footer"],
              "debug"                  => false,
              "allow_output_buffering" => true,
              "showImageErrors"        => false,
              "mirrorMargins"          => false,
              "autoPageBreak"          => false,
              "setAutoBottomMargin"    => false,
              "watermarkImgBehind"     => false,
              "watermarkImgAlphaBlend" => $daynamic_params["watermark_blend"],
              "autoLangToFont"         => true,
              "defaultPageNumStyle"    => "arabic-indic",
            ), $order, $template_pdf_setting, $opts));

            $opts = apply_filters("puiw_generate_pdf_name_orderid_format", array(
              "invoice_prefix" => $this->fn->get_invoice_prefix(),
              "invoice_suffix" => $this->fn->get_invoice_suffix(),
              "invoice_start"  => $this->fn->get_invoice_start(),
            ));
            $order_id_formatted = $opts["invoice_prefix"] . ($opts["invoice_start"]+$order_id) . $opts["invoice_suffix"] ? $opts["invoice_prefix"] . ($opts["invoice_start"]+$order_id) . $opts["invoice_suffix"] : "0000000000000000";
            $pdf_title          = sprintf(_x("Invoice #%s on %s", "invoice-template", $PeproUltimateInvoice->td), "<strong>{$order_id_formatted}</strong>", get_bloginfo('title'));
            $pdf_title          = apply_filters("puiw_generate_pdf_title_of_pdf",$pdf_title);
            $datenow            = current_time('timestamp');
            $mpdf->SetDirectionality($dire);
            $mpdf->SetTitle(strip_tags($pdf_title));
            $mpdf->SetSubject(strip_tags($pdf_title));
            $mpdf->SetAuthor($PeproUltimateInvoice->title_d);
            $mpdf->SetCreator($PeproUltimateInvoice->title_tw);
            if (!empty($daynamic_params["watermark"])) {
              // @see https://mpdf.github.io/reference/mpdf-functions/setwatermarkimage.html
              $wtrmrk_img      = apply_filters("puiw_generate_pdf_watermark_img", $daynamic_params["watermark"], $order_id, $order, "PDF");
              $wtrmrk_alpha    = apply_filters("puiw_generate_pdf_watermark_alpha", (float) $daynamic_params["watermark_opacity_10"], $order_id, $order, "PDF");
              $wtrmrk_size     = apply_filters("puiw_generate_pdf_watermark_size", "D", $order_id, $order, "PDF");
              $wtrmrk_position = apply_filters("puiw_generate_pdf_watermark_position", "P", $order_id, $order, "PDF");
              $mpdf->SetWatermarkImage($wtrmrk_img, $wtrmrk_alpha, $wtrmrk_size, $wtrmrk_position);
              $mpdf->showWatermarkImage = apply_filters("puiw_generate_pdf_watermark_show", true, $order_id, $order, "PDF");
            }
            if (!$order) {
              $errrxt = _x('Error! Invoice does not exist.', 'invoice-template', $PeproUltimateInvoice->td);
              $err_html .= "<body dir='$dire'><h2 style='text-align:center;'>$errrxt</h2><p style='text-align:center;' dir='$dire'>" .
              sprintf(_x('Created by %s<br>( %s )', 'invoice-template', $PeproUltimateInvoice->td), $PeproUltimateInvoice->title_t,"<a href='https://pepro.dev/'>".$PeproUltimateInvoice->title_d.'</a>') .
              "</p><br><span><hr style='width: 80%;'><p style='text-align:center;' dir='$dire'>" .
              sprintf(_x('%sBack to Dashboard%s', 'invoice-template', $PeproUltimateInvoice->td), "<a href='".get_permalink(get_option('woocommerce_myaccount_page_id'))."'>", '</a>'). " / " .
              sprintf(_x('%sBack to Orders%s', 'invoice-template', $PeproUltimateInvoice->td), "<a href='".wc_get_endpoint_url('orders', '', get_permalink(get_option('woocommerce_myaccount_page_id')))."'>", '</a>').
              "</span></p></body>";
              $mpdf->WriteHTML($err_html);
            }
            else{

              $stylesheet      = $this->get_pdf_style($order_id,$order);
              $PDF_EXTRA_STYLE = $this->create_html($order_id, "PDF_EXTRA_STYLE","","",$skipAuth);
              $stylesheet      = $PDF_EXTRA_STYLE . $stylesheet;
              $html_invoice    = $this->create_html($order_id, "PDF","","",$skipAuth);
              $html_header     = $this->create_html($order_id, "PDF", "header","",$skipAuth);
              $html_footer     = $this->create_html($order_id, "PDF", "footer","",$skipAuth);
              $footerhtml      = "<div class='footerauto' style='text-align: center; padding: 1rem;' dir='$dire'><table width='100%'><tr>
                <td style=\"padding: 1rem; text-align: center; width: 33%;\">"._x("Page","invoice-footer",$this->td)." {PAGENO} / {nbpg}</td>
                <td style=\"padding: 1rem; text-align: center; width: 33%;\">{$pdf_title}</td>
                <td style=\"padding: 1rem; text-align: center; width: 33%;\">{$PeproUltimateInvoice->title_t} (https://pepro.dev)</td>
              <tr></table></div>";
              $footerhtml = apply_filters_deprecated("puiw_printinvoice_pdf_footer", [$footerhtml, "", "", $order, $order_id], "1.9.0", "puiw_printinvoice_pdf_footer_new");
              $footerhtml = apply_filters("puiw_printinvoice_pdf_footer_new", $footerhtml, $order, $order_id);
              $mpdf->SetHTMLHeader( $html_header );
              $mpdf->SetHTMLFooter( $html_footer . $footerhtml);
              $mpdf->WriteHTML($stylesheet, \Mpdf\HTMLParserMode::HEADER_CSS);
              $mpdf->WriteHTML($html_invoice, \Mpdf\HTMLParserMode::HTML_BODY);
            }

            $datetime = date_i18n("Y_m_d_H_i_s", $datenow);
            if ($this->fn->get_date_shamsi() == "yes") {
              $datetime = pu_jdate("Y_m_d_H_i_s", (int) $datenow, "", "local", "en");
            }
            $name = "Invoice-$order_id_formatted-$datetime";
            $name = apply_filters("puiw_get_export_pdf_name", $name, $order_id_formatted, $order_id, $datenow);
            if ("S" == $MODE){
              $namedir    = PEPROULTIMATEINVOICE_DIR . "/pdf_temp";
              $namedotext = "Invoice-$order_id_formatted.$datetime.pdf";
              $namedir    = apply_filters( "puiw_get_default_mail_pdf_temp_path", $namedir, $order_id);
              $namedotext = apply_filters( "puiw_get_default_mail_pdf_temp_name", $namedotext, $order_id);
              wp_mkdir_p($namedir);
              $tmpname = "$namedir/$namedotext";
              $mpdf->Output($tmpname, "F");
              return $namedotext;
            }
            $mpdf->Output($name . ".pdf", ($force_download ? "D" : "I"));
            
          } catch (\Mpdf\MpdfException $e) {
            error_log("puiw debugging ~> ".var_export($e, 1));
            wp_die($e->getMessage());
          }

        }
        public function create_slips_pdf($order_id=0, $force_download = false, $MODE="I", $showerror=true)
        {
          if (!$order_id || empty(trim($order_id)) || !is_numeric(trim($order_id))){ return __('Incorrect data!', $this->td); }
          (int) $order_id = trim($order_id);
          $order = wc_get_order($order_id);
          if (!$order) {return false;}
          $skipAuth = true;
          if ("S" !== $MODE){
            $skipAuth = false;
            if (!$this->has_access("PDF",$order)){ global $PeproUltimateInvoice; $PeproUltimateInvoice->die("printClass_create_pdf auth_check", __("Err 403 - Access Denied", $this->td), $PeproUltimateInvoice->Unauthorized_Access); }
          }
          if (!$this->CheckPDFRequirements()){ $this->CheckPDFRequirements($showerror); }
          global $PeproUltimateInvoice;
          require_once PEPROULTIMATEINVOICE_DIR . '/include/vendor/autoload.php';
          $class                   = "pepro-one-page-purchase---invoice-simple " . is_rtl() ? "rtl" : "";
          $dire                    = is_rtl() ? 'rtl' : 'ltr';
          $texe                    = is_rtl() ? 'right' : 'left';
          $defaultConfig           = (new \Mpdf\Config\ConfigVariables())->getDefaults();
          $fontDirs                = $defaultConfig['fontDir'];
          $defaultFontConfig       = (new \Mpdf\Config\FontVariables())->getDefaults();
          $fontData                = $defaultFontConfig['fontdata'];
          $template                = $this->fn->get_template();
          $templateDirpath         = apply_filters( "puiw_get_template_dir_path", $template, $order);
          $contents                = file_get_contents("$templateDirpath/default.cfg");
          $template_pdf_setting    = $this->parseTemplate($contents);
          $get_allow_pdf_customer  = $this->fn->get_allow_pdf_customer();
          $get_pdf_size            = $this->fn->get_pdf_size() . ("L" == $this->fn->get_pdf_orientation() ? "-L" : "");
          $_fontData               = $fontData + [
            'dejavu' => [
              'R' => 'DejaVuSans.ttf',
              'B' => 'DejaVuSans-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iranyekanen' => [
              'R' => 'IRANYekanRegular.ttf',
              'B' => 'IRANYekanBold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iranyekanfa' => [
              'R' => 'IRANYekanRegular(FaNum).ttf',
              'B' => 'IRANYekanBold(FaNum).ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iransans' => [
              'R' => 'IRANSans.ttf',
              'B' => 'IRANSans_Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'iransansfa' => [
              'R' => 'IRANSans(FaNum).ttf',
              'B' => 'IRANSans(FaNum)_Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'danaen' => [
              'R' => 'Dana-Regular.ttf',
              'B' => 'Dana-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ],
            'danafa' => [
              'R' => 'Dana-FaNum-Regular.ttf',
              'B' => 'Dana-FaNum-Bold.ttf',
              'useOTL' => 0xFF,
              'useKashida' => 75,
            ]];

          @ini_set('display_errors', 0);
          error_reporting(0);

          $mpdf = new \Mpdf\Mpdf(apply_filters("puiw_create_slips_pdf_Mpdf_options", array(
            'fontDir'                => array_merge($fontDirs, [plugin_dir_path(__FILE__)]),
            'fontdata'               => $_fontData,
            'default_font'           => $this->fn->get_pdf_font(),
            'format'                 => $get_pdf_size, // A4-L
            'mode'                   => 'utf-8',
            'margin_right'           => $template_pdf_setting["pdf_margin_right"],
            'margin_left'            => $template_pdf_setting["pdf_margin_left"],
            'margin_top'             => $template_pdf_setting["pdf_margin_top"],
            'margin_bottom'          => $template_pdf_setting["pdf_margin_bottom"],
            'margin_header'          => $template_pdf_setting["pdf_margin_header"],
            'margin_footer'          => $template_pdf_setting["pdf_margin_footer"],
            'debug'                  => false,
            'allow_output_buffering' => true,
            'showImageErrors'        => false,
            'mirrorMargins'          => 0,
            'autoLangToFont'         => true,
            '4defaultPageNumStyle'    => 'arabic-indic',
          ), $order, $template_pdf_setting, $opts));
          $opts = apply_filters( "puiw_generate_pdf_name_orderid_format", array(
            "invoice_prefix"=> $this->fn->get_invoice_prefix(),
            "invoice_suffix"=> $this->fn->get_invoice_suffix(),
            "invoice_start"=> $this->fn->get_invoice_start(),
          ));
          $order_id_formatted = $opts["invoice_prefix"] . ($opts["invoice_start"]+$order_id) . $opts["invoice_suffix"] ? $opts["invoice_prefix"] . ($opts["invoice_start"]+$order_id) . $opts["invoice_suffix"] : "0000000000000000";
          $pdf_title          = sprintf(_x("Invoice #%s on %s", "invoice-template", $PeproUltimateInvoice->td), $order_id_formatted, get_bloginfo('title'));
          $pdf_title          = apply_filters( "puiw_generate_pdf_title_of_pdf",$pdf_title);
          $datenow            = current_time('timestamp');
          $mpdf->SetDirectionality($dire);
          $mpdf->SetTitle($pdf_title);
          $mpdf->SetSubject($pdf_title);
          $mpdf->SetAuthor($PeproUltimateInvoice->title_d);
          $mpdf->SetCreator($PeproUltimateInvoice->title_tw);
          if (!$order) {
            $errrxt = _x('Error! Invoice does not exist.', 'invoice-template', $PeproUltimateInvoice->td);
            $err_html .= "<body dir='$dire'><h2 style='text-align:center;'>$errrxt</h2><p style='text-align:center;' dir='$dire'>" .
            sprintf(_x('Created by %s<br>( %s )', 'invoice-template', $PeproUltimateInvoice->td), $PeproUltimateInvoice->title_t,"<a href='https://pepro.dev/'>".$PeproUltimateInvoice->title_d.'</a>') .
            "</p><br><span><hr style='width: 80%;'><p style='text-align:center;' dir='$dire'>" .
            sprintf(_x('%sBack to Dashboard%s', 'invoice-template', $PeproUltimateInvoice->td), "<a href='".get_permalink(get_option('woocommerce_myaccount_page_id'))."'>", '</a>'). " / " .
            sprintf(_x('%sBack to Orders%s', 'invoice-template', $PeproUltimateInvoice->td), "<a href='".wc_get_endpoint_url('orders', '', get_permalink(get_option('woocommerce_myaccount_page_id')))."'>", '</a>').
            "</span></p></body>";
            $mpdf->WriteHTML($err_html);
          }
          else{
            $stylesheet      = $this->get_pdf_style($order_id, $order);
            $PDF_EXTRA_STYLE = $this->create_slips($order_id, "CSS");
            $html_invoice    = $this->create_slips($order_id, "PDF");
            $mpdf->WriteHTML($stylesheet.$PDF_EXTRA_STYLE, \Mpdf\HTMLParserMode::HEADER_CSS);
            $mpdf->WriteHTML($html_invoice, \Mpdf\HTMLParserMode::HTML_BODY);
          }
          $datetime = date_i18n("Y_m_d_H_i", $datenow);
          if ($this->fn->get_date_shamsi() == "yes") {
            $datetime = pu_jdate("Y-m-d_H-i-s", (int) $datenow, "", "local", "en");
          }
          $name = "PackingSlip-$order_id_formatted-$datetime";
          $name = apply_filters("puiw_get_export_pdf_name", $name , $order_id_formatted, $order_id, $datenow);
          if ("S" == $MODE){
            $rand       = md5(time());
            $namedir    = PEPROULTIMATEINVOICE_DIR . "/pdf_temp";
            $namedotext = "PackingSlip-$order_id_formatted.$datetime.pdf";
            $namedir    = apply_filters( "puiw_get_default_mail_pdf_temp_path", $namedir);
            $namedotext = apply_filters( "puiw_get_default_mail_pdf_temp_name", $namedotext);
            wp_mkdir_p($namedir);
            $tmpname = "$namedir/$namedotext";
            $er      = $mpdf->Output($tmpname, "F");
            return $namedotext;
          }
          $mpdf->Output($name . ".pdf", ($force_download ? "D" : "I"));
        }
        public function create_slips($order_id=0, $MODE="HTML")
        {
          if (!$order_id || empty(trim($order_id)) || !is_numeric(trim($order_id))) {return __('Incorrect data!', $this->td);}
          (int) $order_id = trim($order_id);
          $order          = wc_get_order($order_id);
          if (!$order) {return __('Incorrect Order!', $this->td);}
          ob_start();
          $opts                  = $this->get_default_dynamic_params($order_id,$order);
          $opt                   = apply_filters("puiw_printslips_create_html_options", $opts, $order);
          $templateDirpath       = apply_filters("puiw_get_template_dir_path",  $opt["template"], $order);
          $opt["CURENT_DIR_URL"] = apply_filters("puiw_get_template_dir_url",   plugin_dir_url($opt["template"]) ,$opt["template"] ,$order);
          $keepOriginalHTMLtags  = $this->get_preserve_html_tags($opt, $order);
          $keepOriginalENnumbers = $this->get_preserve_english_numbers($opt, $order);
          do_action("puiw_printslips_before_create_html", $opt, $opts, $order);
          $extrainvoiceheaddata  = '';
          $main_css_style        = file_get_contents("$templateDirpath/style.slips".("PDF" == $MODE || "CSS" == $MODE ? ".pdf" : "").".css");
          $body_content          = "PDF" == $MODE ? "" : '<p style="text-align:center;"><a class="print-button" href="javascript:;" onclick="window.print();return false;">'.__("PRINT",$this->td).'</a></p>';
          $body_content         .= file_get_contents("$templateDirpath/template.slips".("PDF" == $MODE ? ".pdf" : "").".tpl");
          $invoicehtmltitle      = "PDF" == $MODE ? "" : "{{{invoice_title}}} | {{{store_name}}}";
          $order_note_a          = apply_filters( "puiw_printslips_order_note_customer", "<strong>".__("Note provided by Customer",$this->td)."</strong><br>" . $this->fn->get_order_note($order,"a") , $this->fn->get_order_note($order,"a"), $order, $opt);
          $order_note_b          = apply_filters( "puiw_printslips_order_note_shopmngr", "<strong>".__("Note provided by Shop manager",$this->td)."</strong><br>" . $this->fn->get_order_note($order,"b") , $this->fn->get_order_note($order,"b"), $order, $opt);

          switch ($opt["show_order_note"]) {
            case 'note_provided_by_customer':
              $notes = "<td>$order_note_a</td>";
              $opt["show_order_note"] = "yes";
              break;
            case 'note_provided_by_shop_manager':
              $notes = "<td>$order_note_b</td>";
              $opt["show_order_note"] = "yes";
              break;
            case 'note_provided_by_both':
              $notes = "<td>$order_note_b</td>
                        <td>$order_note_a</td>";
              $opt["show_order_note"] = "yes";
              break;
            default:
              $notes = "";
              $opt["show_order_note"] = "no";
              break;
          }
          foreach ($opt as $key => $value) {
            if (substr($key,0,5) == "show_" && $value !== "yes"){
              $main_css_style .= "[if~='$key']{display:none !important;}.$key{display:none !important;}";
            }
          }
          if (trim($opt["watermark"]) == ""){
            $main_css_style .= '[if~="watermark"]{display:none !important;}';
            $main_css_style .= '."watermark{display:none !important;}';
          }

          if ($opt["show_invoices_id_barcode"] !== "yes"){
            $opt["show_invoices_id_barcode_colspan"] = 2 ;
          }
          if ($opt["show_shipping_ref_id"] !== "yes"){
            $opt["show_shipping_ref_id_colspan"] = 2;
          }
          if ($opt["show_product_weight"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
          }
          if ($opt["show_product_dimensions"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
            $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] -1 ;
          }

          if ($opt["show_discount_precent"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
            $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] -1 ;
          }
          if ($opt["show_product_tax"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
            $opt["invoice_final_prices_colspan"] = $opt["invoice_final_prices_colspan"] -1 ;
          }

          if ($opt["show_product_sku"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
          }
          if ($opt["show_product_image"] !== "yes"){
            $opt["invoice_final_row_colspan"] = $opt["invoice_final_row_colspan"] -1 ;
            $opt["invoice_final_prices_pre_colspan"] = $opt["invoice_final_prices_pre_colspan"] -1 ;
          }
          $opt["invoice_notes"] = $notes;

          $body_content         = apply_filters( "puiw_printslips_HTML_body", $body_content);
          $extrainvoiceheaddata = apply_filters( "puiw_printslips_HTML_extrahead", $extrainvoiceheaddata);
          $invoicehtmltitle     = apply_filters( "puiw_printslips_HTML_title", $invoicehtmltitle);
          $main_css_style       = apply_filters( "puiw_printslips_HTML_style", $main_css_style);
          $template_css         = "{$main_css_style}{{{custom_css_style}}}";
          $template             = "<!DOCTYPE html><html lang=\"fa\" dir=\"ltr\"><head><title>$invoicehtmltitle</title>$extrainvoiceheaddata<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><style type='text/css'>{$main_css_style}{{{custom_css_style}}}</style></head>$body_content</html>";
          $template             = "PDF" == $MODE ? $body_content : $template;
          $product_row_RAW      = file_get_contents("$templateDirpath/template.row.tpl");
          $n                    = 0;$total_weight = 0;
          foreach ( apply_filters( "puiw_order_items", $order->get_items(), $order) as $item_id => $item ) {
            $n             += 1;
            $product_row    = ($product_row_RAW);
            $product_id     = $item->get_product_id();
            $variation_id   = $item->get_variation_id();
            $somemeta       = $item->get_meta('_whatever', true);
            $product        = $item->get_product();
            $type           = $item->get_type();
            $active_price   = $product->get_price(); // The product active raw price
            $sale_price     = $product->get_sale_price(); // The product raw sale price
            $regular_price  = $product->get_regular_price(); // The product raw regular price
            $name           = apply_filters( "puiw_invoice_item_get_name",              $item->get_name(), $product, $item, $order);
            $extra_classes  = apply_filters( "puiw_invoice_item_extra_classes",         [], $product, $item_id, $item, $order, $n);
            $quantity       = apply_filters( "puiw_invoice_item_get_quantity",          $item->get_quantity(), $product, $item, $order);
            $subtotal       = apply_filters( "puiw_invoice_item_get_subtotal",          wc_price($item->get_subtotal()), $product, $item, $order);
            $total          = apply_filters( "puiw_invoice_item_get_total",             wc_price($item->get_total()), $product, $item, $order);
            $tax            = apply_filters( "puiw_invoice_item_get_subtotal_tax",      wc_price($item->get_subtotal_tax()), $product, $item, $order);
            $taxclass       = apply_filters( "puiw_invoice_item_get_tax_class",         $item->get_tax_class(), $product, $item, $order);
            $taxstat        = apply_filters( "puiw_invoice_item_get_tax_status",        $item->get_tax_status(), $product, $item, $order);
            $allmeta        = apply_filters( "puiw_invoice_item_get_meta_data",         $item->get_meta_data(), $product, $item, $order);
            $description    = apply_filters( "puiw_invoice_item_get_purchase_note",     $product->get_purchase_note(), $product, $item, $order);
            $description   .= $this->get_item_meta($item_id, $item, $product);
            $weight_raw     = apply_filters( "puiw_invoice_item_get_product_weight_raw",$product->get_weight() , $product, $item, $order);
            $weight         = apply_filters( "puiw_invoice_item_get_product_weight",    $this->fn->get_format_weight($weight_raw), $product, $item, $order);
            $dimension      = apply_filters( "puiw_invoice_item_get_product_dimension", $this->fn->get_product_dimension($item->get_product_id()), $product, $item, $order);
            $percentage     = (100-((float)$item->get_total() / (float)$item->get_subtotal() * 100));
            $percentage     = ($percentage > 0) ? sprintf("%2d%%", $percentage) : "00.0%";
            $discount       = apply_filters( "puiw_invoice_item_get_product_discount", $percentage, $product, $item, $order);
            $sku            = $product->get_sku();
            if ($opt["show_product_sku2"] == "yes"){$sku  = empty($sku) || !$sku ? "#$product_id" : $sku;}
            $product_weight = $weight_raw ? $weight_raw : 0;
              if ($product_weight) {
                $total_weight += floatval( $product_weight * $quantity );
                $opt["invoice_total_weight"] = apply_filters( "puiw_printslips_calculate_invoice_total_weight", $this->fn->get_format_weight($total_weight), $total_weight, $product_weight, $quantity, $product, $item, $order);
              }
              $opt["invoice_total_qty"] = (int) $opt["invoice_total_qty"] + $quantity;
              switch ($opt["show_price_template"]) {
                //show_only_regular_price, show_only_sale_price, show_both_regular_and_sale_price
                case 'show_only_regular_price':
                  $base_price = wc_price($product->get_regular_price(), array( 'currency' => $order->get_currency() ));
                  break;
                case 'show_only_sale_price':
                  $base_price = wc_price($product->get_sale_price(), array( 'currency' => $order->get_currency() ));
                  break;
                case 'show_both_regular_and_sale_price':
                  $base_price = wc_price($product->get_price(), array( 'currency' => $order->get_currency() ));
                  break;
                default:
			            $base_price = wc_price( $order->get_item_subtotal( $item, false, true ), array( 'currency' => $order->get_currency() ) );
                  break;
              }

              if ($this->is_bundled_child($item_id)){
                $base_price = "";
                $subtotal = "";
                if ($this->_woosb_show_bundled_hierarchy == "yes"){$n--;}
              }

              $optm = array(
                "n"             => $n,
                "img"           => ("PDF" == $MODE) ? $product->get_image(array( 50, 50 )) : $product->get_image('shop_thumbnail'),
                "sku"           => $sku,
                "title"         => $name,
                "qty"           => $quantity,
                "base_price"    => $base_price,
                "description"   => $description,
                "extra_classes" => implode(" ", (array) $extra_classes),
                "discount"      => $discount,
                "weight"        => $weight,
                "total_weight"  => apply_filters( "puiw_printslips_create_html_total_weight", $this->fn->get_format_weight(floatval($product_weight*$quantity)),
                floatval($product_weight*$quantity),$product_weight, $quantity, $item_id, $item, $product_id, $order ),
                "dimension"       => $dimension,
                "tax"             => $tax,
                "nettotal"        => $subtotal,
                "shelf_number_id" => get_post_meta( $product_id, "_shelf_number_id", true),
              );
              $optm = apply_filters( "puiw_printslips_create_html_item_row_metas", $optm, $item_id, $item, $product_id, $order );

              foreach ($optm as $key => $value) {
                  if (!in_array($key, $keepOriginalENnumbers)) {
                    $value = $this->fn->parse_number($value);
                  }
                  $product_row = str_replace("{{{{$key}}}}", $value, $product_row);
              }
              $opt["invoice_products_list"] .= $product_row;
          }
          foreach ($opt as $key => $value) {
            if (!in_array($key, $keepOriginalENnumbers)) {
              $value = $this->fn->parse_number($value);
            }
            $value = apply_filters("puiw_printslips_create_html_options_{$key}_value", $value, $key, $order);
            if (!in_array($key, $keepOriginalHTMLtags)){
              $template_css = str_replace("{{{{$key}}}}", wp_strip_all_tags($value, 1), ($template_css));
              $template      = str_replace("{{{{$key}}}}", wp_strip_all_tags($value, 1), ($template));
            }
            else{
              $template_css = str_replace("{{{{$key}}}}", $value, $template_css);
              $template      = str_replace("{{{{$key}}}}", $value, $template);
            }
          }
          if(apply_filters("puiw_printslips_return_html_minfied", true, $template, $opt, $order)){
            $template = $this->minify_html($template);
          }
          if ("CSS" == $MODE) { return $template_css; }
          do_action("puiw_printslips_after_create_html", $opt, $opts, $order);
          do_action("puiw_printslips_before_return_html", $opt, $opts, $order);
          echo apply_filters("puiw_printslips_return_html", $template, $opt, $opts, $order);
          do_action("puiw_printslips_after_return_html", $opt, $opts, $order);
          $html_output = ob_get_contents();
          ob_end_clean();
          return $html_output;
        }
        public function create_inventory($order_id=0, $MODE="HTML")
        {
          if (!$order_id || empty(trim($order_id)) || !is_numeric(trim($order_id))) {return __('Incorrect data!', $this->td);}
          (int) $order_id = trim($order_id);
          $order = wc_get_order($order_id);
          if (!$order) {return __('Incorrect Order!', $this->td);}
          ob_start();
          $opts = $this->get_default_dynamic_params($order_id,$order);
          $opt = apply_filters("puiw_printinventory_create_html_options", $opts, $order);

          $templateDirpath = apply_filters( "puiw_get_template_dir_path", $opt["template"], $order);
          $opt["CURENT_DIR_URL"] = apply_filters( "puiw_get_template_dir_url", plugin_dir_url($opt["template"]) ,$opt["template"] ,$order);

          $keepOriginalHTMLtags = $this->get_preserve_html_tags($opt, $order);
          $keepOriginalENnumbers = $this->get_preserve_english_numbers($opt, $order);
          do_action("puiw_printinventory_before_create_html", $opt, $opts, $order);
          $extrainvoiceheaddata = '';
          $main_css_style = file_get_contents("$templateDirpath/style.inventory.css");
          $body_content = '<p style="text-align:center;"><a class="print-button" href="javascript:;" onclick="window.print();return false;">'.__("PRINT",$this->td).'</a></p>';
          $body_content .= file_get_contents("$templateDirpath/template.inventory.tpl");
          $invoicehtmltitle = "{{{invoice_title}}} | {{{store_name}}}";
          $extrainvoiceheaddata .= '<script src="'.PEPROULTIMATEINVOICE_URL.'/assets/js/qrcode.min.js"></script>';
          $order_note_a = apply_filters( "puiw_printinventory_order_note_customer", "<strong>".__("Note provided by Customer",$this->td)."</strong><br>" . $this->fn->get_order_note($order,"a") , $this->fn->get_order_note($order,"a"), $order, $opt);
          $order_note_b = apply_filters( "puiw_printinventory_order_note_shopmngr", "<strong>".__("Note provided by Shop manager",$this->td)."</strong><br>" . $this->fn->get_order_note($order,"b") , $this->fn->get_order_note($order,"b"), $order, $opt);
          $opt["show_inventory_price"] = "yes";
          if ($opt["price_inventory_report"] == "hide_all_price") { $opt["show_inventory_price"] = "no"; }
          switch ($opt["show_order_note_inventory"]) {
            case 'note_provided_by_customer':
              $notes = "<td>$order_note_a</td>";
              $opt["show_inventory_note"] = "yes";
              break;
            case 'note_provided_by_shop_manager':
              $notes = "<td>$order_note_b</td>";
              $opt["show_inventory_note"] = "yes";
              break;
            case 'note_provided_by_both':
              $notes = "<td>$order_note_b</td><td>$order_note_a</td>";
              $opt["show_inventory_note"] = "yes";
              break;
            default:
              $notes = "";
              $opt["show_inventory_note"] = "no";
              break;
          }
          foreach ($opt as $key => $value) { if (substr($key,0,5) == "show_" && $value != "yes"){ $main_css_style .= "[if~='$key'],.$key{display:none !important;}"; } }
          $opt["invoice_final_prices_pre_colspan"] = $nmpo = 8;
          if (trim($opt["watermark"]) == ""){ $main_css_style .= '[if~="watermark"]{display:none !important;}.watermark{display:none !important;}'; }
          if ($opt["show_product_image_inventory"] !== "yes"){ $nmpo-=1; }
          if ($opt["show_product_sku_inventory"] !== "yes"){ $nmpo-=1; }
          if ($opt["show_shelf_number_id"] !== "yes"){ $nmpo-=1; }
          if ($opt["show_inventory_price"] !== "yes"){ $nmpo-=1; }
          if ($opt["show_product_weight_in_inventory"] !== "yes"){ $nmpo-=1; }
          $opt["invoice_final_prices_pre_colspan"] = $nmpo;
          $opt["invoice_notes"] = $notes;
          $body_content = apply_filters( "puiw_printinventory_HTML_body", $body_content);
          $extrainvoiceheaddata = apply_filters( "puiw_printinventory_HTML_extrahead", $extrainvoiceheaddata);
          $invoicehtmltitle = apply_filters( "puiw_printinventory_HTML_title", $invoicehtmltitle);
          $main_css_style = apply_filters( "puiw_printinventory_HTML_style", $main_css_style);
          $template = "<!DOCTYPE html><html lang=\"fa\" dir=\"ltr\"><head><title>$invoicehtmltitle</title>$extrainvoiceheaddata<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><style type='text/css'>{$main_css_style}{{{inventory_css_style}}}</style></head>$body_content</html>";
          $product_row_RAW = file_get_contents("$templateDirpath/template.row.inventory.tpl");
          $n=0;$total_weight = 0;
          foreach ( apply_filters( "puiw_order_items", $order->get_items(), $order) as $item_id => $item ) {
              $n+=1;
              $product_row  = ($product_row_RAW);
              $product_id   = $item->get_product_id();
              $variation_id = $item->get_variation_id();
              $somemeta     = $item->get_meta('_whatever', true);
              $product      = $item->get_product();
              $type         = $item->get_type();
              $active_price = $product->get_price(); // The product active raw price
              $sale_price   = $product->get_sale_price(); // The product raw sale price
              $regular_price= $product->get_regular_price(); // The product raw regular price
              $name         = apply_filters( "puiw_invoice_item_get_name",              $item->get_name(), $product, $item, $order);
              $extra_classes= apply_filters( "puiw_invoice_item_extra_classes",         [], $product, $item_id, $item, $order, $n);
              $quantity     = apply_filters( "puiw_invoice_item_get_quantity",          $item->get_quantity(), $product, $item, $order);
              $subtotal     = apply_filters( "puiw_invoice_item_get_subtotal",          wc_price($item->get_subtotal()), $product, $item, $order);
              $total        = apply_filters( "puiw_invoice_item_get_total",             wc_price($item->get_total()), $product, $item, $order);
              $tax          = apply_filters( "puiw_invoice_item_get_subtotal_tax",      wc_price($item->get_subtotal_tax()), $product, $item, $order);
              $taxclass     = apply_filters( "puiw_invoice_item_get_tax_class",         $item->get_tax_class(), $product, $item, $order);
              $taxstat      = apply_filters( "puiw_invoice_item_get_tax_status",        $item->get_tax_status(), $product, $item, $order);
              $allmeta      = apply_filters( "puiw_invoice_item_get_meta_data",         $item->get_meta_data(), $product, $item, $order);
              $description  = apply_filters( "puiw_invoice_item_get_purchase_note",     $product->get_purchase_note(), $product, $item, $order);
              $description .= $this->get_item_meta($item_id, $item, $product);
              $weight_raw   = apply_filters( "puiw_invoice_item_get_product_weight_raw",$product->get_weight() , $product, $item, $order);
              $weight       = apply_filters( "puiw_invoice_item_get_product_weight",    $this->fn->get_format_weight($weight_raw), $product, $item, $order);
              $dimension    = apply_filters( "puiw_invoice_item_get_product_dimension", $this->fn->get_product_dimension($item->get_product_id()), $product, $item, $order);
              $percentage   = (100-((float)$item->get_total() / (float)$item->get_subtotal() * 100));
              $percentage   = ($percentage > 0) ? sprintf("%2d%%", $percentage) : "00.0%";
              $discount     = apply_filters( "puiw_invoice_item_get_product_discount", $percentage, $product, $item, $order);
              $sku          = $product->get_sku();
              if ($opt["show_product_sku2_inventory"] == "yes"){
               $sku = empty($sku) || !$sku ? "#$product_id" : $sku;
              }
              $product_weight = $weight_raw ?$weight_raw: 0;
              if ($product_weight) {
                $total_weight += floatval( $product_weight * $quantity );
                $opt["invoice_total_weight"] = apply_filters( "puiw_printinventory_calculate_invoice_total_weight", $this->fn->get_format_weight($total_weight), $total_weight, $product_weight, $quantity, $product, $item, $order);
              }
              $opt["invoice_total_qty"] = (int) $opt["invoice_total_qty"] + $quantity;
              switch ($opt["price_inventory_report"]) {
                //show_only_regular_price, show_only_sale_price, show_both_regular_and_sale_price
                case 'show_only_regular_price':
                  $base_price = wc_price($product->get_regular_price(), array( 'currency' => $order->get_currency() ));
                  break;
                case 'show_only_sale_price':
                  $base_price = wc_price($product->get_sale_price(), array( 'currency' => $order->get_currency() ));
                  break;
                case 'show_both_regular_and_sale_price':
                  // $opt["show_product_image"] = "yes";
                  $base_price = wc_price($product->get_price(), array( 'currency' => $order->get_currency() ));
                  break;
                case 'hide_all_price':
                  $base_price = "";
                  break;
                default:
                  // $base_price = wc_price($item->get_total() / $item->get_quantity());
		              $base_price = wc_price( $order->get_item_subtotal( $item, false, true ), array( 'currency' => $order->get_currency() ) );
                  break;
              }

              if ($this->is_bundled_child($item_id)){
                $base_price = "";
                $subtotal = "";
                if ($this->_woosb_show_bundled_hierarchy == "yes"){$n--;}
              }

              $optm = array(
                "n" => $n,
                "img" => ("PDF" == $MODE) ? $product->get_image(array( 50, 50 )) : $product->get_image('shop_thumbnail'),
                "sku" => $sku,
                "title" => $name,
                "qty" => $quantity,
                "base_price" => $base_price,
                "description" => $description,
                "extra_classes" => implode(" ", (array) $extra_classes),
                "discount" => $discount,
                "weight" => $weight,
                "total_weight" => apply_filters( "puiw_printinventory_create_html_total_weight", $this->fn->get_format_weight(floatval($product_weight*$quantity)),
                floatval($product_weight*$quantity),$product_weight, $quantity, $item_id, $item, $product_id, $order ),
                "dimension" => $dimension,
                "tax" => $tax,
                "nettotal" => $subtotal,
                "shelf_number_id" => get_post_meta( $product_id, "_shelf_number_id", true),
              );
              $optm = apply_filters( "puiw_printinventory_create_html_item_row_metas", $optm, $item_id, $item, $product_id, $order );

              foreach ($optm as $key => $value) {
                  if (!in_array($key, $keepOriginalENnumbers)) {
                    $value = $this->fn->parse_number($value);
                  }
                  $product_row = str_replace("{{{{$key}}}}", $value, $product_row);
              }
              $opt["invoice_products_list"] .= $product_row;
          }
          foreach ($opt as $key => $value) {
            if (!in_array($key, $keepOriginalENnumbers)) {
              $value = $this->fn->parse_number($value);
            }
            $value = apply_filters("puiw_printinventory_create_html_options_{$key}_value", $value, $key, $order);
            if (!in_array($key, $keepOriginalHTMLtags)){
              $template = str_replace("{{{{$key}}}}", wp_strip_all_tags($value, 1), ($template));
            }
            else{
              $template = str_replace("{{{{$key}}}}", $value, $template);
            }
          }
          if(apply_filters("puiw_printinventory_return_html_minfied", true, $template, $opt, $order)){
            $template = $this->minify_html($template);
          }
          do_action("puiw_printinventory_after_create_html", $opt, $opts, $order);
          do_action("puiw_printinventory_before_return_html", $opt, $opts, $order);
          echo apply_filters("puiw_printinventory_return_html", $template, $opt, $opts, $order);
          do_action("puiw_printinventory_after_return_html", $opt, $opts, $order);
          $html_output = ob_get_contents();
          ob_end_clean();
          return $html_output;
        }
        protected function CheckPDFRequirements($print = false, $forHTML=false)
        {
          $ok = true;
          $items = array(
            "mbstring"          => "extension",
            "mb_regex_encoding" => "function",
            "gd"                => "extension",
            "zlib"              => "extension",
            "bcmath"            => "extension",
            "xml"               => "extension",
            "curl"              => "extension",
          );
          if (true == $forHTML) {
            $items = array(
              "gd"              => "extension"
            );
          }
          foreach ( $items as $key => $value) {
              if ($print){
                if ("extension" == $value) {
                  echo extension_loaded($key) ?
                  "<p>Extension <strong>".ucfirst($key)."</strong>: OK</p>" :
                  "<p>Extension <strong>".ucfirst($key)."</strong>: DOES NOT EXISTS</p>";
                }else{
                  echo function_exists($key) ?
                  "<p>Function <strong>".ucfirst($key)."</strong>: OK</p>" :
                  "<p>Function <strong>".ucfirst($key)."</strong>: DOES NOT EXISTS</p>";
                }
              }
              else{
                if (false == $ok){ return false; continue;}
                if ("extension" == $value){
                  if (!extension_loaded($key)){ $ok = false; }
                }
                else{
                  if (!function_exists($key)){ $ok = false; }
                }
              }

          }
          return $ok;
        }
        protected function CheckPDFRequirementsHTML($print = false)
        {
          return $this->CheckPDFRequirements($print, true);
        }
        protected function puiw__download_file($url)
        {
            // Initialize the cURL session
            $ch = curl_init($url);
            // Use basename() function to return
            // the base name of file
            $file_name = basename($url);
            // Save file into file location
            $save_file_loc = plugin_dir_path(__FILE__) . "logo.png";
            // Open file
            $fp = fopen($save_file_loc, 'wb');
            // It set an option for a cURL transfer
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            // Perform a cURL session
            curl_exec($ch);
            // Closes a cURL session and frees all resources
            curl_close($ch);
            // Close file
            fclose($fp);
            return $save_file_loc;
        }
        protected function get_pdf_style($order_id=0, $order=false)
        {
          $template = $this->fn->get_template();
          $templateDirpath = apply_filters( "puiw_get_template_dir_path", $template, $order);
          $template = file_get_contents("$templateDirpath/style.pdf.css");
          $opts = $this->get_default_dynamic_params($order_id,$order);
          $opts["invoice_final_prices"] = $this->get_order_final_prices_pdf($order);
          $opt = apply_filters("puiw_printinvoice_create_html_options", $opts, $order);
          $opt["CURENT_DIR_URL"] = apply_filters( "puiw_get_template_dir_url", plugin_dir_url($template) ,$template ,$order);

          $keepOriginalHTMLtags = $this->get_preserve_html_tags($opt, $order);
          $keepOriginalENnumbers = $this->get_preserve_english_numbers($opt, $order);
          foreach ($opt as $key => $value) {
            if (!in_array($key, $keepOriginalENnumbers)) {
              $value = $this->fn->parse_number($value);
            }
            $value = apply_filters("puiw_printinvoice_create_html_options_{$key}_value", $value, $key, $order);
            if (!in_array($key, $keepOriginalHTMLtags)){
              $template = str_replace("{{{{$key}}}}", wp_strip_all_tags($value, 1), ($template));
            }
            else{
              $template = str_replace("{{{{$key}}}}", $value, $template);
            }
          }
          return $template;
        }
        protected function minify_html($input)
        {
            if(trim($input) === "") return $input;
            // Remove extra white-space(s) between HTML attribute(s)
            $input = preg_replace_callback(
                '#<([^\/\s<>!]+)(?:\s+([^<>]*?)\s*|\s*)(\/?)>#s', function ($matches) {
                    return '<' . $matches[1] . preg_replace('#([^\s=]+)(\=([\'"]?)(.*?)\3)?(\s+|$)#s', ' $1$2', $matches[2]) . $matches[3] . '>';
                }, str_replace("\r", "", $input)
            );
              // Minify inline CSS declaration(s)
            if(strpos($input, ' style=') !== false) {
                $input = preg_replace_callback(
                    '#<([^<]+?)\s+style=([\'"])(.*?)\2(?=[\/\s>])#s', function ($matches) {
                        return '<' . $matches[1] . ' style=' . $matches[2] . $this->minify_css($matches[3]) . $matches[2];
                    }, $input
                );
            }
            if(strpos($input, '</style>') !== false) {
                $input = preg_replace_callback(
                    '#<style(.*?)>(.*?)</style>#is', function ($matches) {
                        return '<style' . $matches[1] .'>'. $this->minify_css($matches[2]) . '</style>';
                    }, $input
                );
            }
            if(strpos($input, '</script>') !== false) {
                $input = preg_replace_callback(
                    '#<script(.*?)>(.*?)</script>#is', function ($matches) {
                        return '<script' . $matches[1] .'>'. $this->minify_js($matches[2]) . '</script>';
                    }, $input
                );
            }

            $minified = preg_replace(
                array(
                // t = text
                // o = tag open
                // c = tag close
                // Keep important white-space(s) after self-closing HTML tag(s)
                '#<(img|input)(>| .*?>)#s',
                // Remove a line break and two or more white-space(s) between tag(s)
                '#(<!--.*?-->)|(>)(?:\n*|\s{2,})(<)|^\s*|\s*$#s',
                '#(<!--.*?-->)|(?<!\>)\s+(<\/.*?>)|(<[^\/]*?>)\s+(?!\<)#s', // t+c || o+t
                '#(<!--.*?-->)|(<[^\/]*?>)\s+(<[^\/]*?>)|(<\/.*?>)\s+(<\/.*?>)#s', // o+o || c+c
                '#(<!--.*?-->)|(<\/.*?>)\s+(\s)(?!\<)|(?<!\>)\s+(\s)(<[^\/]*?\/?>)|(<[^\/]*?\/?>)\s+(\s)(?!\<)#s', // c+t || t+o || o+t -- separated by long white-space(s)
                '#(<!--.*?-->)|(<[^\/]*?>)\s+(<\/.*?>)#s', // empty tag
                '#<(img|input)(>| .*?>)<\/\1>#s', // reset previous fix
                '#(&nbsp;)&nbsp;(?![<\s])#', // clean up ...
                '#(?<=\>)(&nbsp;)(?=\<)#', // --ibid
                // Remove HTML comment(s) except IE comment(s)
                '#\s*<!--(?!\[if\s).*?-->\s*|(?<!\>)\n+(?=\<[^!])#s'
                ),
                array(
                '<$1$2</$1>',
                '$1$2$3',
                '$1$2$3',
                '$1$2$3$4$5',
                '$1$2$3$4$5$6$7',
                '$1$2$3',
                '<$1$2',
                '$1 ',
                '$1',
                ""
                ),
                $input
            );
            return (null !== $minified && !empty($minified)) ? $minified : $input;
        }
        protected function minify_css($input)
        {
            if(trim($input) === "") return $input;
            $minified = preg_replace(
                array(
                // Remove comment(s)
                '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')|\/\*(?!\!)(?>.*?\*\/)|^\s*|\s*$#s',
                // Remove unused white-space(s)
                '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/))|\s*+;\s*+(})\s*+|\s*+([*$~^|]?+=|[{};,>~+]|\s*+-(?![0-9\.])|!important\b)\s*+|([[(:])\s++|\s++([])])|\s++(:)\s*+(?!(?>[^{}"\']++|"(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')*+{)|^\s++|\s++\z|(\s)\s+#si',
                // Replace `0(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)` with `0`
                '#(?<=[\s:])(0)(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)#si',
                // Replace `:0 0 0 0` with `:0`
                '#:(0\s+0|0\s+0\s+0\s+0)(?=[;\}]|\!important)#i',
                // Replace `background-position:0` with `background-position:0 0`
                '#(background-position):0(?=[;\}])#si',
                // Replace `0.6` with `.6`, but only when preceded by `:`, `,`, `-` or a white-space
                '#(?<=[\s:,\-])0+\.(\d+)#s',
                // Minify string value
                '#(\/\*(?>.*?\*\/))|(?<!content\:)([\'"])([a-z_][a-z0-9\-_]*?)\2(?=[\s\{\}\];,])#si',
                '#(\/\*(?>.*?\*\/))|(\burl\()([\'"])([^\s]+?)\3(\))#si',
                // Minify HEX color code
                '#(?<=[\s:,\-]\#)([a-f0-6]+)\1([a-f0-6]+)\2([a-f0-6]+)\3#i',
                // Replace `(border|outline):none` with `(border|outline):0`
                '#(?<=[\{;])(border|outline):none(?=[;\}\!])#',
                // Remove empty selector(s)
                '#(\/\*(?>.*?\*\/))|(^|[\{\}])(?:[^\s\{\}]+)\{\}#s'
                ),
                array(
                '$1',
                '$1$2$3$4$5$6$7',
                '$1',
                ':0',
                '$1:0 0',
                '.$1',
                '$1$3',
                '$1$2$4$5',
                '$1$2$3',
                '$1:0',
                '$1$2'
                ),
                $input
            );
            return (null !== $minified && !empty($minified)) ? $minified : $input;
        }
        protected function minify_js($input)
        {
            if(trim($input) === "") return $input;
            $minified = preg_replace(
                array(
                // Remove comment(s)
                '#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*(?=[\n\r]|$)|^\s*|\s*$#',
                // Remove white-space(s) outside the string and regex
                '#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s',
                // Remove the last semicolon
                '#;+\}#',
                // Minify object attribute(s) except JSON attribute(s). From `{'foo':'bar'}` to `{foo:'bar'}`
                '#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i',
                // --ibid. From `foo['bar']` to `foo.bar`
                '#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i'
                ),
                array(
                '$1',
                '$1$2',
                '}',
                '$1$3',
                '$1.$3'
                ),
                $input
            );
            return (null !== $minified && !empty($minified)) ? $minified : $input;
        }
        /**
         * hook to alter css styles
         *
         * @method  custom_css_per_invoice
         * @param   string $custom_css_style
         * @param   string $default
         * @return  string
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function custom_css_per_invoice($custom_css_style, $default)
        {
          if ($this->_woosb_show_bundled_hierarchy == "yes"){
            $custom_css_style .= "tr.even {background: var(--theme_color) !important;}";
            $custom_css_style .= "tr.odd {background: white !important;}";
            $custom_css_style .= ".woosb-order-item.woosb-item-child .show_product_image *,.woosb-order-item.woosb-item-child .show_product_n * {display: none;}";
          }
          return $custom_css_style;
        }
        /**
         * Get Order Final Prices
         *
         * @method  get_order_final_prices
         * @param   WC_Order $order
         * @return  string
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function get_order_final_prices($order)
        {
          ob_start();
          echo '<table style="width: 100%;float: left;">';
          foreach ( $order->get_order_item_totals() as $key => $total ) {
            ?>
            <tr class="puiw_totalrow <?php echo $key;?>">
              <th style="border: none;"scope="row"><?php echo esc_html( $total['label'] ); ?></th>
              <td style="border: none;"><?php echo ( 'payment_method' === $key ) ? esc_html( $total['value'] ) : wp_kses_post( $total['value'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
            </tr>
            <?php
          }
          echo "</table>";
          $tr = ob_get_contents();
          $tr = apply_filters( "puiw_printinvoice_get_order_final_prices", $tr, $order);
          ob_end_clean();
          return $tr;
        }
        /**
         * Get Order Final Prices Pdf
         *
         * @method  get_order_final_prices_pdf
         * @param   WC_Order $order
         * @return  string
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function get_order_final_prices_pdf($order)
        {
          ob_start();
          foreach ( $order->get_order_item_totals() as $key => $total ) {
            echo "<p dir='rtl'>" . esc_html($total['label']) . " " . (( 'payment_method' === $key ) ? esc_html( $total['value'] ) : wp_kses_post( $total['value'] )) . "</p><br>";
          }
          $tr = ob_get_contents();
          $tr = apply_filters( "puiw_printinvoice_get_order_final_prices_pdf", $tr, $order);
          ob_end_clean();
          return apply_filters("puiw_return_pdf_total_prices_as_single_price", false , $order) ? $order->get_order_item_totals()["order_total"]["value"] : $tr;
        }
        /**
         * show item meta supporting WPC Product Bundles and wc hooks
         *
         * @param   int $item_id
         * @param   Object $item
         * @param   WC_Product $product
         * @return  string
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        private function get_item_meta($item_id, $item, $product)
        {
          ob_start();
          $ob_get_contents = ""; $echo = ""; $found_any = false;
          if (!$item || empty($item)) return '';
          $hidden_order_itemmeta = apply_filters('woocommerce_hidden_order_itemmeta', array( '_qty', '_tax_class', '_product_id', '_variation_id', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', 'method_id', 'cost', '_reduced_stock', ) );

          do_action( 'woocommerce_before_order_itemmeta', $item_id, $item, $product );

          if ( $meta_data = $item->get_formatted_meta_data('') ) {
            $echo .= "<div class='view order_item_meta'><div cellspacing='0' class='display_meta'>";
            foreach ( $meta_data as $meta_id => $meta ){
              if ( in_array( $meta->key, $hidden_order_itemmeta, true ) ) { continue; }
              if ($this->_woosb_show_bundles_subtitle == "no" && "bundled-products" === sanitize_title($meta->key,"")){ continue; }
              if ($this->_woosb_show_bundles_subtitle == "yes" && "bundled-products" === sanitize_title($meta->key,"")){ $meta->display_key = $this->_woosb_show_bundles_prefix; }
              $found_any = true;
              $echo .= "<div style='background: unset;' class='". sanitize_title("$meta->key","") ."'>
                      <span class='itemmeta_label' style='font-weight: bold'>" . wp_kses_post( $meta->display_key ) . ":</span>
                      <span class='itemmeta_value'> " . strip_tags(force_balance_tags( $meta->display_value ) ) . "</span>
              </div>";
            }
            if ($found_any){
              echo "$echo</div></div>";
            }
            $ob_get_contents = ob_get_contents();
            ob_end_clean();
          }

          do_action( 'woocommerce_after_order_itemmeta', $item_id, $item, $product );

          return $ob_get_contents;
        }
        /**
         * WPC Product Bundles Hide Bundles Parent
         *
         * @method  woosb_puiw_hide_bundles_parent
         * @param   array $data_list
         * @param   WC_Order $order
         * @return  array
         * @version 1.0.0
         * @since   1.0.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function woosb_puiw_hide_bundles_parent( $data_list, $order )
        {
          foreach ( $data_list as $key => $data ) {
            $bundles = wc_get_order_item_meta( $key, '_woosb_ids', true );
            if ( ! empty( $bundles ) ) {
              unset( $data_list[ $key ] );
            }
          }
          return $data_list;
        }
        /**
         * WPC Product Bundles Hide Bundled Childs
         *
         * @method  woosb_puiw_hide_bundled_childs
         * @param   array $data_list
         * @param   WC_Order $order
         * @return  array
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function woosb_puiw_hide_bundled_childs( $data_list, $order )
        {
          foreach ( $data_list as $key => $data ) {
            $bundled = wc_get_order_item_meta( $key, '_woosb_parent_id', true );
            if ( ! empty( $bundled ) ) {
              unset( $data_list[ $key ] );
            }
          }
          return $data_list;
        }
        /**
         * WPC Product Bundles isBundledParent
         *
         * @method  is_bundled_parent
         * @param   string $key
         * @return  boolean
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function is_bundled_parent($key)
        {
          return wc_get_order_item_meta( $key, '_woosb_ids', true );
        }
        /**
         * WPC Product Bundles isBundledChild
         *
         * @method  is_bundled_child
         * @param   string $key
         * @return  boolean
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function is_bundled_child($key)
        {
          return wc_get_order_item_meta( $key, '_woosb_parent_id', true );
        }
        /**
         * invoice items tr html classes
         *
         * @method  puiw__item_extra_classes
         * @param   array $classes
         * @param   WC_Product $product
         * @param   int $item_id
         * @param   Object $item
         * @param   WC_Order $order
         * @param   int $nthitem
         * @return  array classes
         * @version 1.0.0
         * @since   1.0.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function puiw__item_extra_classes($classes, $product, $item_id, $item, $order, $nthitem)
        {
          if ($nthitem % 2) {
            $odd_even = "odd";
          } else {
            $odd_even = "even";
          }

          global $puiw_last_woosb_bundle_parent_index, $puiw_last_woosb_bundle_child_index;


          if ($this->is_bundled_parent($item_id)){
            $classes[] = "woosb-order-item woosb-item-parent";
            if ($this->_woosb_show_bundled_hierarchy == "yes"){
              $puiw_last_woosb_bundle_child_index = false;
              $puiw_last_woosb_bundle_parent_index = $nthitem;
              $classes[] = $odd_even;
              return $classes;
            }
          }
          if ($this->is_bundled_child($item_id)){
            $classes[] = "woosb-order-item woosb-item-child";
            if ($this->_woosb_show_bundled_hierarchy == "yes"){
              if ($puiw_last_woosb_bundle_parent_index % 2){$odd_even = "odd";}else{$odd_even = "even";}
              $puiw_last_woosb_bundle_child_index = $nthitem;
              $classes[] = $odd_even;
              return $classes;
            }
          }
          if ($this->_woosb_show_bundled_hierarchy == "yes"){
            if ($puiw_last_woosb_bundle_child_index && $puiw_last_woosb_bundle_child_index>0){
              if ( ( $nthitem - 1 -$puiw_last_woosb_bundle_child_index ) % 2) {
                $odd_even = "odd";
              } else {
                $odd_even = "even";
              }
              $classes[] = $odd_even;
              return $classes;
            }
          }

          $classes[] = $odd_even;
          return $classes;
        }
        /**
         * add bundled in to bundled products child
         *
         * @method  woosb_before_order_item_meta
         * @param   int $order_item_id
         * @return  string
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function woosb_before_order_item_meta($order_item_id)
        {
          if ( $parent_id = wc_get_order_item_meta( $order_item_id, '_woosb_parent_id', true ) ) {
            if ($this->_woosb_show_bundled_subtitle == "yes"){
              echo $this->_woosb_show_bundled_prefix." ".get_the_title($parent_id);
            }
          }
        }
        /**
         * Sort Order Items
         *
         * @method  puiw_sort_order_items
         * @param   array $items
         * @param   WC_Order $order
         * @return  array $items
         * @version 1.0.0
         * @since   1.3.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        public function puiw_sort_order_items($items, $order)
        {
          if( count($items) > 1 ) {
            $item_qty = array();
            $item_order = array();
            $sorted_items = array();
            $sort_by = apply_filters( "puiw_order_items_sort_by", $this->fn->get_items_sorting("NONE"));
            if ( !$sort_by || empty($sort_by) || $sort_by == "NONE" ){return $items;}
            foreach( $items as $items_id => $item ){
              if( $item->is_type('line_item') && method_exists( $item, 'get_product' ) ){
                $product = $item->get_product();
                if( is_a( $product, 'WC_Product' ) ) {
                  $item_order_data = array(
                    "ID" => $items_id,
                    'PID' => $item->get_product_id(),
                    'SKU' => $product->get_sku(),
                    'QTY' => $item->get_quantity(),
                    'NAME' => $item->get_name(),
                    'PRICE' => $order->get_item_subtotal( $item, false, true ),
                    'TOTAL' => $item->get_total(),
                    'WEIGHT' => $product->get_weight(),
                    'SUBTOTAL' => $item->get_subtotal(),
                    'SUBTOTAL_TAX' => $item->get_subtotal_tax(),
                  );
                  $item_order[$items_id] = apply_filters( "puiw_order_items_sort_by_force", $item_order_data, $item_order, $items_id, $item, $product, $items, $sort_by);
                  $item_order[$items_id]["_id"] = $items_id;
                }
              }
            }
            if(!empty($item_order)){
              if (apply_filters( "puiw_order_items_sort_desc", false) === false){
                $col = array_column( $item_order, $sort_by );
                array_multisort( $col, SORT_ASC, $item_order );
              }
              else{
                $col = array_column( $item_order, $sort_by );
                array_multisort( $col, SORT_DESC, $item_order );
              }
              foreach( $item_order as $i => $x ){
                $sorted_items[$x["_id"]] = $items[$x["_id"]];
              }
              return $sorted_items;
            }
          }
          return $items;
        }
        /**
         * read css file header and info
         *
         * @method parseTemplate
         * @param string $contents css content
         * @return array header info
         * @version 2.0.0
         * @since 1.0.0
         * @license https://pepro.dev/license Pepro.dev License
         */
        private function parseTemplate($contents) {
          $styleExifDAta = array();
          foreach (explode("\n", $contents) as $line) {
            $data = explode(":", $line);
            if (count($data) == 2) {
              $styleExifDAta[strtolower(trim($data[0]))] = trim($data[1]);
            }
          }
          return apply_filters("puiw_parse_pdf_template", $styleExifDAta, $contents);
        }
    }
}
/*##################################################
Lead Developer: [amirhp-com](https://amirhp.com/)
##################################################*/
