HEX
Server: Apache
System: Linux sxb1plzcpnl440011.prod.sxb1.secureserver.net 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: xfp2mtarcm67 (7705020)
PHP: 7.3.33
Disabled: NONE
Upload Files
File: //proc/self/cwd/wp-content/plugins/fin-accounting-for-woocommerce/classes/inventory.class.php
<?php
/**
 * Class for Inventory management
 *
 *
 * @link              https://finpose.com
 * @since             2.1.0
 * @package           Finpose
 * @author            [email protected]
 */
if ( !class_exists( 'fin_inventory' ) ) {
  class fin_inventory extends fin_app {

    public $table = 'fin_inventory';
    public $v = 'getInventory';
    public $p = '';

    public $selyear;
    public $selmonth;
    public $selcat = '';
    public $selpage;

    public $success = false;
    public $message = '';
    public $payload = array();
    public $callback = '';

      /**
     * Constructor
     */
    public function __construct($v = 'getInventory') {
      parent::__construct();

      $this->selyear = $this->curyear;
      $this->selmonth = $this->curmonth;
      $this->view['settings'] = $this->settings;

      // POST verification, before processing
      if($this->post) {
        $validated = $this->validate();
        if($validated) {
          $verified = wp_verify_nonce( $this->post['nonce'], 'finpost' );
          $can = current_user_can( 'view_woocommerce_reports' );
          if($verified && $can) {

            if(isset($this->post['process'])) {
              $p = $this->post['process'];

              unset(
                $this->post['process'],
                $this->post['handler'],
                $this->post['action'],
                $this->post['nonce'],
                $this->post['_wp_http_referer']
              );

              $this->$p();
            }
          }
        }
      }

      if($v != 'ajax') {
        $args = array(
            'status' => 'publish',
        );


        $this->$v();
      }

      if($this->ask->errmsg) { $this->view['errmsg'] = $this->ask->errmsg; }
    }

    /**
   * Validate all inputs before use
   */
    public function validate() {
      $status = true;

      foreach ($this->post as $pk => $pv) {
        if($pk == 'type') {
          if(!in_array($pv, array_keys($this->presets->costTypes))) {
            $status = false;
            $this->message = esc_html__( 'Invalid Type', 'finpose' );
          }
        }
        if($pk == 'paidwith') {
          if(strlen($pv)>32) {
            $status = false;
            $this->message = esc_html__( 'Invalid Paid With Information', 'finpose' );
          }
        }
        if($pk == 'items') {
          if($pv != intval($pv)) {
            $status = false;
            $this->message = esc_html__( 'Invalid items', 'finpose' );
          }
        }
        if($pk == 'page') {
          if($pv != intval($pv)) {
            $status = false;
            $this->message = esc_html__( 'Invalid page', 'finpose' );
          }
        }
        if(in_array($pk, array('amount', 'tr'))) {
          if($pv!='0.00' && !preg_match('/^(?!0\.00)\d{1,3}(,\d{3})*(\.\d\d)?$/', $pv)) {
            $status = false;
            $this->message = esc_html__( 'Invalid money format', 'finpose' );
          }
        }
        if($pk == 'name') {
          if(strlen($pv)>128) {
            $status = false;
            $this->message = esc_html__( 'Name can not be longer than 128 characters', 'finpose' );
          }
        }
        if($pk == 'notes') {
          if(strlen($pv)>512) {
            $status = false;
            $this->message = esc_html__( 'Notes can not be longer than 512 characters', 'finpose' );
          }
        }
        if($pk == 'datepaid') {
          if(!preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $pv)) {
            $status = false;
            $this->message = esc_html__( 'Date format provided is invalid', 'finpose' );
          }
        }
        if($pk == 'year') {
          if(intval($pv)>2030||intval($pv)<2010) {
            $status = false;
            $this->message = esc_html__( 'Year provided is invalid', 'finpose' );
          }
        }
        if($pk == 'month') {
          if(intval($pv)>12||intval($pv)<1) {
            $status = false;
            $this->message = esc_html__( 'Month provided is invalid', 'finpose' );
          }
        }
      }

    return $status;
    }

    /**
   * Before inventory page loaded
   */
    public function pageInventory() {
      $orderby = 'name';
      $order = 'asc';
      $hide_empty = false ;
      $cat_args = array(
          'orderby'    => $orderby,
          'order'      => $order,
          'hide_empty' => $hide_empty,
      );
       
      $product_categories = get_terms( 'product_cat', $cat_args );
      $this->view['cats'] = $product_categories;      
    }

    /**
   * Helper to get inventory module specific data for the given product
   */
    private function getFinmeta($product) {
      $product->wc_quantity = $product->get_stock_quantity();
      $product->name = $product->get_name();
      $product->price = $product->get_price();
      $product->pid = $product->get_id();
      $product->type = ucfirst($product->get_type());

      $product->finmeta = $this->ask->selectRow("SELECT COUNT(iid) AS units, AVG(cost) AS avgcost, SUM(cost) AS totalvalue FROM fin_inventory WHERE siteid='%d' AND pid = '%d' AND is_sold='%d'", array($this->view['siteid'], $product->pid, 0));
      if(!(floatval($product->finmeta->avgcost))) { $product->finmeta->avgcost = 0; }
      if(!(floatval($product->finmeta->totalvalue))) { $product->finmeta->totalvalue = 0; }
      
      $product->finmeta->margin = 0;
      if($product->finmeta->avgcost && $product->price && $product->finmeta->avgcost) {
        $product->finmeta->margin = ((100 * ($product->price - $product->finmeta->avgcost)) / $product->price);
      }

      $sold = $this->ask->selectRows("SELECT * FROM fin_inventory WHERE siteid='%d' AND pid = '%d' AND is_sold='%d' ORDER BY timesold DESC LIMIT 50", array($this->view['siteid'], $product->pid, 1));
      $numsold = count($sold); 
      
      if(!isset($product->finmeta->units)) {
        $product->finmeta->units = 0;
      }

      if($product->wc_quantity > $product->finmeta->units) {
        $product->finmeta->import = true;
      } else {
        $product->finmeta->import = false;
      }
      
      if($numsold<5) {
        $product->finmeta->rodate = esc_html__( 'Waiting more data', 'finpose' );;
      } else {
        if($product->finmeta->units<1) {
          $product->finmeta->rodate = esc_html__( 'Out of stock', 'finpose' );;
        } else {
          $lastSale = current($sold)->timesold;
          $now = time();
          $firstSale = end($sold)->timesold;
          $product->diff = $now - $firstSale;
          $avgunix = ($now - $firstSale)/$numsold;
          $timetogo = $product->finmeta->units * $avgunix;
          $result = time() + $timetogo; //$lastSale
          $product->finmeta->rodate = $this->dateFormat($result);
        }
      }
      
    return $product;
    }
    

    /**
   * Get all store products and prepare inventory data
   */
    private function getProducts() {
      global $wpdb;

      $filters = json_decode(stripslashes($this->post['filters']), true);
      $this->payload['pager'] = json_decode(stripslashes($this->post['pager']), true);
      
      $args = array(
          //'status'    => 'publish',
          //'type' => array('', 'simple', 'grouped', 'variable'),
          'orderby' => 'name',
          'order'   => 'ASC',
          'limit' => $this->payload['pager']['perpage'],
          'page'  => $this->payload['pager']['page'],
          'paginate' => true,
      );

      if($filters['type']) { $args['type'] = $filters['type']; }
      if($filters['category']) { $args['category'] = array($filters['category']); }
      if($filters['term']) { $args['like_name'] = $filters['term']; }

      $result = wc_get_products($args);
      $this->payload['pager']['total'] = $result->total;
      $this->payload['pager']['pages'] = $result->max_num_pages;
      
      $prdlist = array();
      foreach ($result->products as $key => $product) {
        if ($product->get_type() == "variable") {
          if($product->get_manage_stock()) {
            $prdlist[] = $this->getFinmeta($product);
          } else {
            $varmanage = false;
            foreach ($product->get_children() as $vid) {
              $variation_obj = new WC_Product_variation($vid);
              if($variation_obj->get_manage_stock()) { $varmanage = true; }
              $prdlist[] = $this->getFinmeta($variation_obj);
            }
            if(!$varmanage) {
              $prdlist[] = $this->getFinmeta($product);
            }
          }
        } else {
          $prdlist[] = $this->getFinmeta($product);
        }
      }
      $this->payload['products'] = $prdlist;
    }

    /**
   * Inventory module entry page method
   */
    private function getInventory() {
      $this->getProducts();
      $this->payload['summary'] = $this->ask->selectRow("SELECT COUNT(iid) AS units, SUM(cost) AS totalvalue FROM fin_inventory WHERE siteid='%d' AND is_sold='%d'", array($this->view['siteid'], 0));
      $this->payload['summary']->lastupdate = $this->dateFormat($this->ask->getVar("SELECT timecr FROM fin_inventory WHERE siteid='%d' ORDER BY timecr DESC LIMIT %d", array($this->view['siteid'], 1)));
      if($this->post['initial'] == 'true') {
        $this->payload['accounts'] = $this->getAccounts();
        $this->payload['vendors'] = $this->ask->selectRows("SELECT * FROM fin_vendors WHERE siteid='%d' ORDER BY vname ASC", array($this->view['siteid']));
      }
    }

    /**
   * Inventory needs Sync
   */

    private function getNeedSync() {
      $args = [
        //'status'    => 'publish',
        //'type' => array('', 'simple', 'grouped', 'variable'),
        'orderby' => 'name',
        'order'   => 'ASC',
        'limit' => -1,
      ];
      $products = wc_get_products($args);

      $prdlist = array();
      foreach ($products as $key => $product) {
        if ($product->get_type() == "variable") {
          if($product->get_manage_stock()) {
            $prdmeta = $this->getFinmeta($product);
            if($prdmeta->finmeta->import) { $prdlist[] = $prdmeta; }
          } else {
            $varmanage = false;
            foreach ($product->get_children() as $vid) {
              $variation_obj = new WC_Product_variation($vid);
              if($variation_obj->get_manage_stock()) { $varmanage = true; }
              $prdmeta = $this->getFinmeta($variation_obj);
              if($prdmeta->finmeta->import) { $prdlist[] = $prdmeta; }
            }
            if(!$varmanage) {
              $prdmeta = $this->getFinmeta($product);
              if($prdmeta->finmeta->import) { $prdlist[] = $prdmeta; }
            }
          }
        } else {
          $prdmeta = $this->getFinmeta($product);
          if($prdmeta->finmeta->import) { $prdlist[] = $prdmeta; }
        }

        //echo $prdmeta->name;
      }
      $this->payload['products'] = $prdlist;
    }

    /**
   * Add more stock for given product
   */
    private function addStock() {
    global $wpdb;
      $now = time();
      $numunits = $this->post['units'];
      $unsold = $this->ask->getVar("SELECT COUNT(iid) FROM fin_inventory WHERE siteid='%d' AND is_sold='%d' AND pid='%s'", array($this->view['siteid'], 0, $this->post['pid']));
      $add = false;
      $totalValue = (float)$this->moneyToDB($this->post['unitcost']) * (int)$this->post['units'];
      $product = wc_get_product( $this->post['pid'] );

      for($i=1;$i<=(int)$numunits;$i++) {
        $iarr = array();
        $iarr['iid'] = str_shuffle($this->randomChars());
        $iarr['siteid'] = $this->view['siteid'];
        $iarr['pid'] = $this->post['pid'];
        $iarr['vid'] =  $this->post['vid'];
        $iarr['is_sold'] = 0;
        $iarr['cost'] = $this->moneyToDB($this->post['unitcost']);
        $iarr['timecr'] = $now+$i;
        $add = $this->put->insert($this->table, $iarr);
      }

      if($this->post['import'] == '0') {
        if(!$product->get_manage_stock()) { $product->set_manage_stock(true); }
        $product->set_stock_quantity($unsold + $this->post['units']);
        $product->save();
      }
      
      if(isset($this->post['savecost']) && $this->post['savecost']=='1') {
        $copy = array();
        $copy['coid'] = $this->randomChars();
        $copy['siteid'] = $this->view['siteid'];
        $copy['cat'] = 'inventory';
        $copy['amount'] = $totalValue;
        $copy['tr'] = $this->moneyToDB($this->post['tr']);
        $copy['datepaid'] = time();
        $copy['timecr'] = time();
        $copy['vid'] = $this->post['vid'];
        $copy['paidwith'] = $this->post['paidwith'];
        $copy['items'] = $product->get_id();
        $copy['name'] = $product->get_name().' x '.$this->post['units'];
        $copy['notes'] = esc_html__( 'Added by inventory module', 'finpose' );
        
        $addcost = $this->put->insert('fin_costs', $copy);
      }

      if($add) {
        $this->success = true;
        $this->payload = (int)$numunits;
        $this->message = esc_html__( 'Added new units successfully', 'finpose' );
      } else {
        $this->message = esc_html__( 'Unable to add new units', 'finpose' );
      }
    }

    public function getProduct() {
      $pid = $this->post['pid'];
      $prod = wc_get_product($pid);
      $this->payload = array('id'=>$pid, 'name'=>$prod->get_name());
      $this->success = true;
    }

    public function getInventoryItems() {
      $this->payload['pager'] = json_decode(stripslashes($this->post['pager']), true);

      $pid = $this->post['pid'];
      $product = wc_get_product($pid);
      $this->payload['editor']['product']['sku'] = $product->get_sku();
      $this->payload['editor']['product']['name'] = $product->get_name();
      $this->payload['pager']['total'] = $this->ask->getVar("SELECT COUNT(iid) FROM fin_inventory WHERE siteid='%d' AND pid = '%d'", array($this->view['siteid'], $pid));
      $this->payload['pager']['pages'] = ceil($this->payload['pager']['total']/$this->payload['pager']['perpage']);
      
      $start = $this->payload['pager']['perpage'] * ($this->payload['pager']['page'] - 1);
      $items = $this->ask->selectRows("SELECT * FROM fin_inventory WHERE siteid='%d' AND pid = '%d' ORDER BY timecr DESC LIMIT %d, %d", array($this->view['siteid'], $pid, $start, $this->payload['pager']['perpage']));
      
      $this->payload['editor']['product']['summary']['sold'] = $this->ask->getVar("SELECT COUNT(iid) FROM fin_inventory WHERE siteid='%d' AND pid = '%d' AND is_sold = '%d'", array($this->view['siteid'], $pid, 1));
      $this->payload['editor']['product']['summary']['unsold'] = $this->ask->getVar("SELECT COUNT(iid) FROM fin_inventory WHERE siteid='%d' AND pid = '%d' AND is_sold = '%d'", array($this->view['siteid'], $pid, 0));
      $this->payload['editor']['product']['summary']['total'] = $this->payload['editor']['product']['summary']['sold'] + $this->payload['editor']['product']['summary']['unsold'];
       
      foreach($items as $k=>$item) {
        $item->date_added = $this->dateFormat($item->timecr);
        $item->date_sold = $this->dateFormat($item->timesold);
        if($item->is_sold) {
          $timeinstock = $item->timesold - $item->timecr;
          $item->days_in_stock = round($timeinstock/86400);
        }
        $items[$k] = $item;
      }
      $this->payload['editor']['items'] = $items;
      $this->success = true;
    }

    public function removeInventoryUnit(){
      $iid = $this->post['iid'];
      $del = $this->put->delete("fin_inventory", array('iid' => $iid));
      if($del) {
        $product = wc_get_product( $this->post['pid'] );
        if($product) {
          $fin_stocks = $this->ask->getVar("SELECT COUNT(iid) FROM fin_inventory WHERE siteid='%d' AND pid = '%d' AND is_sold='%d'", array($this->view['siteid'], $this->post['pid'], 0));
          if(!$product->get_manage_stock()) { $product->set_manage_stock(true); }
          $product->set_stock_quantity($fin_stocks);
          $product->save();
        }

        $this->success = true;
        $this->message = esc_html__( 'Removed successfully', 'finpose' );
      } else {
        $this->message = esc_html__( 'Unable to remove', 'finpose' );
      }
    }
  }
}