Overview

Namespaces

  • emberlabs
    • Barcode
  • None

Classes

  • Appconfig
  • Barcode_lib
  • Config
  • Customer
  • Customer_rewards
  • Customers
  • Detailed_receivings
  • Detailed_sales
  • Dinner_table
  • Email_lib
  • emberlabs\Barcode\BarcodeBase
  • emberlabs\Barcode\Code128
  • emberlabs\Barcode\Code39
  • emberlabs\Barcode\Ean13
  • emberlabs\Barcode\Ean8
  • Employee
  • Employees
  • Giftcard
  • Giftcards
  • Home
  • Inventory
  • Inventory_low
  • Inventory_summary
  • Item
  • Item_kit
  • Item_kit_items
  • Item_kits
  • Item_lib
  • Item_quantity
  • Item_taxes
  • Items
  • Login
  • Mailchimp_lib
  • MailchimpConnector
  • Messages
  • Module
  • MY_Lang
  • No_Access
  • Person
  • Persons
  • Receiving
  • Receiving_lib
  • Receivings
  • Report
  • Reports
  • Rewards
  • Rounding_code
  • Sale
  • Sale_lib
  • Sale_suspended
  • Sales
  • Secure_Controller
  • Sms_lib
  • Specific_customer
  • Specific_discount
  • Specific_employee
  • Stock_location
  • Summary_categories
  • Summary_customers
  • Summary_discounts
  • Summary_employees
  • Summary_items
  • Summary_payments
  • Summary_report
  • Summary_sales
  • Summary_suppliers
  • Summary_taxes
  • Supplier
  • Suppliers
  • Tax
  • Tax_lib
  • Taxes
  • Token
  • Token_customer
  • Token_invoice_count
  • Token_invoice_sequence
  • Token_lib
  • Token_quote_sequence
  • Token_suspended_invoice_count
  • Token_year_invoice_count
  • Tracking_lib

Functions

  • currency_side
  • current_language
  • current_language_code
  • dateformat_bootstrap
  • dateformat_momentjs
  • db_log_queries
  • get_customer_data_row
  • get_customer_manage_table_headers
  • get_giftcard_data_row
  • get_giftcards_manage_table_headers
  • get_item_data_row
  • get_item_kit_data_row
  • get_item_kits_manage_table_headers
  • get_items_manage_table_headers
  • get_people_manage_table_headers
  • get_person_data_row
  • get_sale_data_last_row
  • get_sale_data_row
  • get_sales_manage_payments_summary
  • get_sales_manage_table_headers
  • get_supplier_data_row
  • get_suppliers_manage_table_headers
  • get_tax_data_row
  • get_taxes_manage_table_headers
  • load_config
  • load_language_files
  • load_stats
  • parse_decimals
  • pdf_create
  • quantity_decimals
  • show_report
  • show_report_if_allowed
  • to_currency
  • to_currency_no_money
  • to_decimals
  • to_quantity_decimals
  • to_tax_decimals
  • totals_decimals
  • transform_headers
  • transform_headers_readonly
  • Overview
  • Namespace
  • Class
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836: 837: 838: 839: 840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855: 856: 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

require_once("Secure_Controller.php");

class Items extends Secure_Controller
{
    public function __construct()
    {
        parent::__construct('items');

        $this->load->library('item_lib');
    }
    
    public function index()
    {
        $data['table_headers'] = $this->xss_clean(get_items_manage_table_headers());
        
        $data['stock_location'] = $this->xss_clean($this->item_lib->get_item_location());
        $data['stock_locations'] = $this->xss_clean($this->Stock_location->get_allowed_locations());

        // filters that will be loaded in the multiselect dropdown
        $data['filters'] = array('empty_upc' => $this->lang->line('items_empty_upc_items'),
            'low_inventory' => $this->lang->line('items_low_inventory_items'),
            'is_serialized' => $this->lang->line('items_serialized_items'),
            'no_description' => $this->lang->line('items_no_description_items'),
            'search_custom' => $this->lang->line('items_search_custom_items'),
            'is_deleted' => $this->lang->line('items_is_deleted'));

        $this->load->view('items/manage', $data);
    }

    /*
    Returns Items table data rows. This will be called with AJAX.
    */
    public function search()
    {
        $search = $this->input->get('search');
        $limit = $this->input->get('limit');
        $offset = $this->input->get('offset');
        $sort = $this->input->get('sort');
        $order = $this->input->get('order');

        $this->item_lib->set_item_location($this->input->get('stock_location'));

        $filters = array('start_date' => $this->input->get('start_date'),
                        'end_date' => $this->input->get('end_date'),
                        'stock_location_id' => $this->item_lib->get_item_location(),
                        'empty_upc' => FALSE,
                        'low_inventory' => FALSE, 
                        'is_serialized' => FALSE,
                        'no_description' => FALSE,
                        'search_custom' => FALSE,
                        'is_deleted' => FALSE);
        
        // check if any filter is set in the multiselect dropdown
        $filledup = array_fill_keys($this->input->get('filters'), TRUE);
        $filters = array_merge($filters, $filledup);

        $items = $this->Item->search($search, $filters, $limit, $offset, $sort, $order);

        $total_rows = $this->Item->get_found_rows($search, $filters);

        $data_rows = array();
        foreach($items->result() as $item)
        {
            $data_rows[] = $this->xss_clean(get_item_data_row($item, $this));
            if($item->pic_filename!='')
            {
                $this->_update_pic_filename($item);
            }
        }

        echo json_encode(array('total' => $total_rows, 'rows' => $data_rows));
    }
    
    public function pic_thumb($pic_filename)
    {
        $this->load->helper('file');
        $this->load->library('image_lib');

        // in this context, $pic_filename always has .ext
        $ext = pathinfo($pic_filename, PATHINFO_EXTENSION);
        $images = glob('./uploads/item_pics/' . $pic_filename);

        // make sure we pick only the file name, without extension
        $base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
        if(sizeof($images) > 0)
        {
            $image_path = $images[0];
            $thumb_path = $base_path . $this->image_lib->thumb_marker . '.' . $ext;
            if(sizeof($images) < 2)
            {
                $config['image_library'] = 'gd2';
                $config['source_image']  = $image_path;
                $config['maintain_ratio'] = TRUE;
                $config['create_thumb'] = TRUE;
                $config['width'] = 52;
                $config['height'] = 32;
                $this->image_lib->initialize($config);
                $image = $this->image_lib->resize();
                $thumb_path = $this->image_lib->full_dst_path;
            }
            $this->output->set_content_type(get_mime_by_extension($thumb_path));
            $this->output->set_output(file_get_contents($thumb_path));
        }
    }

    /*
    Gives search suggestions based on what is being searched for
    */
    public function suggest_search()
    {
        $suggestions = $this->xss_clean($this->Item->get_search_suggestions($this->input->post_get('term'),
            array('search_custom' => $this->input->post('search_custom'), 'is_deleted' => $this->input->post('is_deleted') != NULL), FALSE));

        echo json_encode($suggestions);
    }

    public function suggest()
    {
        $suggestions = $this->xss_clean($this->Item->get_search_suggestions($this->input->post_get('term'),
            array('search_custom' => FALSE, 'is_deleted' => FALSE), TRUE));

        echo json_encode($suggestions);
    }

    public function suggest_kits()
    {
        $suggestions = $this->xss_clean($this->Item->get_kit_search_suggestions($this->input->post_get('term'),
            array('search_custom' => FALSE, 'is_deleted' => FALSE), TRUE));

        echo json_encode($suggestions);
    }

    /*
    Gives search suggestions based on what is being searched for
    */
    public function suggest_category()
    {
        $suggestions = $this->xss_clean($this->Item->get_category_suggestions($this->input->get('term')));

        echo json_encode($suggestions);
    }

    /*
     Gives search suggestions based on what is being searched for
    */
    public function suggest_location()
    {
        $suggestions = $this->xss_clean($this->Item->get_location_suggestions($this->input->get('term')));

        echo json_encode($suggestions);
    }
    
    /*
     Gives search suggestions based on what is being searched for
    */
    public function suggest_custom()
    {
        $suggestions = $this->xss_clean($this->Item->get_custom_suggestions($this->input->post('term'), $this->input->post('field_no')));

        echo json_encode($suggestions);
    }

    public function get_row($item_ids)
    {
        $item_infos = $this->Item->get_multiple_info(explode(":", $item_ids), $this->item_lib->get_item_location());

        $result = array();
        foreach($item_infos->result() as $item_info)
        {
            $result[$item_info->item_id] = $this->xss_clean(get_item_data_row($item_info, $this));
        }

        echo json_encode($result);
    }

    public function view($item_id = -1)
    {
        $data['item_tax_info'] = $this->xss_clean($this->Item_taxes->get_info($item_id));
        $data['default_tax_1_rate'] = '';
        $data['default_tax_2_rate'] = '';
        $data['item_kits_enabled'] = $this->Employee->has_grant('item_kits', $this->Employee->get_logged_in_employee_info()->person_id);

        $item_info = $this->Item->get_info($item_id);
        foreach(get_object_vars($item_info) as $property => $value)
        {
            $item_info->$property = $this->xss_clean($value);
        }

        if($item_id == -1)
        {
            $data['default_tax_1_rate'] = $this->config->item('default_tax_1_rate');
            $data['default_tax_2_rate'] = $this->config->item('default_tax_2_rate');

            $item_info->receiving_quantity = 0;
            $item_info->reorder_level = 0;
            $item_info->item_type = '0'; // standard
            $item_info->stock_type = '0'; // stock
            $item_info->tax_category_id = 0;
        }

        $data['item_info'] = $item_info;

        $suppliers = array('' => $this->lang->line('items_none'));
        foreach($this->Supplier->get_all()->result_array() as $row)
        {
            $suppliers[$this->xss_clean($row['person_id'])] = $this->xss_clean($row['company_name']);
        }
        $data['suppliers'] = $suppliers;
        $data['selected_supplier'] = $item_info->supplier_id;

        $customer_sales_tax_support = $this->config->item('customer_sales_tax_support');
        if($customer_sales_tax_support == '1')
        {
            $data['customer_sales_tax_enabled'] = TRUE;
            $tax_categories = array();
            foreach($this->Tax->get_all_tax_categories()->result_array() as $row)
            {
                $tax_categories[$this->xss_clean($row['tax_category_id'])] = $this->xss_clean($row['tax_category']);
            }
            $data['tax_categories'] = $tax_categories;
            $data['selected_tax_category'] = $item_info->tax_category_id;
        }
        else
        {
            $data['customer_sales_tax_enabled'] = FALSE;
            $data['tax_categories'] = array();
            $data['selected_tax_category'] = '';
        }

        $data['logo_exists'] = $item_info->pic_filename != '';
        $ext = pathinfo($item_info->pic_filename, PATHINFO_EXTENSION);
        if($ext == '')
        {
            // if file extension is not found guess it (legacy)
            $images = glob('./uploads/item_pics/' . $item_info->pic_filename . '.*');
        }
        else
        {
            // else just pick that file
            $images = glob('./uploads/item_pics/' . $item_info->pic_filename);
        }
        $data['image_path'] = sizeof($images) > 0 ? base_url($images[0]) : '';
        $stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
        foreach($stock_locations as $location)
        {
            $location = $this->xss_clean($location);

            $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity);
            $quantity = ($item_id == -1) ? 0 : $quantity;
            $location_array[$location['location_id']] = array('location_name' => $location['location_name'], 'quantity' => $quantity);
            $data['stock_locations'] = $location_array;
        }

        $this->load->view('items/form', $data);
    }

    public function inventory($item_id = -1)
    {
        $item_info = $this->Item->get_info($item_id);
        foreach(get_object_vars($item_info) as $property => $value)
        {
            $item_info->$property = $this->xss_clean($value);
        }
        $data['item_info'] = $item_info;

        $data['stock_locations'] = array();
        $stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
        foreach($stock_locations as $location)
        {
            $location = $this->xss_clean($location);
            $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity);
        
            $data['stock_locations'][$location['location_id']] = $location['location_name'];
            $data['item_quantities'][$location['location_id']] = $quantity;
        }

        $this->load->view('items/form_inventory', $data);
    }
    
    public function count_details($item_id = -1)
    {
        $item_info = $this->Item->get_info($item_id);
        foreach(get_object_vars($item_info) as $property => $value)
        {
            $item_info->$property = $this->xss_clean($value);
        }
        $data['item_info'] = $item_info;

        $data['stock_locations'] = array();
        $stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
        foreach($stock_locations as $location)
        {
            $location = $this->xss_clean($location);
            $quantity = $this->xss_clean($this->Item_quantity->get_item_quantity($item_id, $location['location_id'])->quantity);
        
            $data['stock_locations'][$location['location_id']] = $location['location_name'];
            $data['item_quantities'][$location['location_id']] = $quantity;
        }

        $this->load->view('items/form_count_details', $data);
    }

    public function generate_barcodes($item_ids)
    {
        $this->load->library('barcode_lib');

        $item_ids = explode(':', $item_ids);
        $result = $this->Item->get_multiple_info($item_ids, $this->item_lib->get_item_location())->result_array();
        $config = $this->barcode_lib->get_barcode_config();

        $data['barcode_config'] = $config;

        // check the list of items to see if any item_number field is empty
        foreach($result as &$item)
        {
            $item = $this->xss_clean($item);
            
            // update the UPC/EAN/ISBN field if empty / NULL with the newly generated barcode
            if(empty($item['item_number']) && $this->config->item('barcode_generate_if_empty'))
            {
                // get the newly generated barcode
                $barcode_instance = Barcode_lib::barcode_instance($item, $config);
                $item['item_number'] = $barcode_instance->getData();
                
                $save_item = array('item_number' => $item['item_number']);

                // update the item in the database in order to save the UPC/EAN/ISBN field
                $this->Item->save($save_item, $item['item_id']);
            }
        }
        $data['items'] = $result;

        // display barcodes
        $this->load->view('barcodes/barcode_sheet', $data);
    }

    public function bulk_edit()
    {
        $suppliers = array('' => $this->lang->line('items_none'));
        foreach($this->Supplier->get_all()->result_array() as $row)
        {
            $row = $this->xss_clean($row);

            $suppliers[$row['person_id']] = $row['company_name'];
        }
        $data['suppliers'] = $suppliers;
        $data['allow_alt_description_choices'] = array(
            '' => $this->lang->line('items_do_nothing'), 
            1  => $this->lang->line('items_change_all_to_allow_alt_desc'),
            0  => $this->lang->line('items_change_all_to_not_allow_allow_desc'));

        $data['serialization_choices'] = array(
            '' => $this->lang->line('items_do_nothing'), 
            1  => $this->lang->line('items_change_all_to_serialized'),
            0  => $this->lang->line('items_change_all_to_unserialized'));

        $this->load->view('items/form_bulk', $data);
    }

    public function save($item_id = -1)
    {
        $upload_success = $this->_handle_image_upload();
        $upload_data = $this->upload->data();

        //Save item data
        $item_data = array(
            'name' => $this->input->post('name'),
            'description' => $this->input->post('description'),
            'category' => $this->input->post('category'),
            'item_type' => $this->input->post('item_type'),
            'stock_type' => $this->input->post('stock_type'),
            'supplier_id' => $this->input->post('supplier_id') == '' ? NULL : $this->input->post('supplier_id'),
            'item_number' => $this->input->post('item_number') == '' ? NULL : $this->input->post('item_number'),
            'cost_price' => parse_decimals($this->input->post('cost_price')),
            'unit_price' => parse_decimals($this->input->post('unit_price')),
            'reorder_level' => parse_decimals($this->input->post('reorder_level')),
            'receiving_quantity' => parse_decimals($this->input->post('receiving_quantity')),
            'allow_alt_description' => $this->input->post('allow_alt_description') != NULL,
            'is_serialized' => $this->input->post('is_serialized') != NULL,
            'deleted' => $this->input->post('is_deleted') != NULL,
            'custom1' => $this->input->post('custom1') == NULL ? '' : $this->input->post('custom1'),
            'custom2' => $this->input->post('custom2') == NULL ? '' : $this->input->post('custom2'),
            'custom3' => $this->input->post('custom3') == NULL ? '' : $this->input->post('custom3'),
            'custom4' => $this->input->post('custom4') == NULL ? '' : $this->input->post('custom4'),
            'custom5' => $this->input->post('custom5') == NULL ? '' : $this->input->post('custom5'),
            'custom6' => $this->input->post('custom6') == NULL ? '' : $this->input->post('custom6'),
            'custom7' => $this->input->post('custom7') == NULL ? '' : $this->input->post('custom7'),
            'custom8' => $this->input->post('custom8') == NULL ? '' : $this->input->post('custom8'),
            'custom9' => $this->input->post('custom9') == NULL ? '' : $this->input->post('custom9'),
            'custom10' => $this->input->post('custom10') == NULL ? '' : $this->input->post('custom10')
        );

        $x = $this->input->post('tax_category_id');
        if(!isset($x))
        {
            $item_data['tax_category_id'] = '';
        }
        else
        {
            $item_data['tax_category_id'] = $this->input->post('tax_category_id');
        }
        
        if(!empty($upload_data['orig_name']))
        {
            // XSS file image sanity check
            if($this->xss_clean($upload_data['raw_name'], TRUE) === TRUE)
            {
                $item_data['pic_filename'] = $upload_data['raw_name'];
            }
        }
        
        $employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
        $cur_item_info = $this->Item->get_info($item_id);
        
        if($this->Item->save($item_data, $item_id))
        {
            $success = TRUE;
            $new_item = FALSE;
            //New item
            if($item_id == -1)
            {
                $item_id = $item_data['item_id'];
                $new_item = TRUE;
            }
            
            $items_taxes_data = array();
            $tax_names = $this->input->post('tax_names');
            $tax_percents = $this->input->post('tax_percents');
            $count = count($tax_percents);
            for ($k = 0; $k < $count; ++$k)
            {
                $tax_percentage = parse_decimals($tax_percents[$k]);
                if(is_numeric($tax_percentage))
                {
                    $items_taxes_data[] = array('name' => $tax_names[$k], 'percent' => $tax_percentage);
                }
            }
            $success &= $this->Item_taxes->save($items_taxes_data, $item_id);

            //Save item quantity
            $stock_locations = $this->Stock_location->get_undeleted_all()->result_array();
            foreach($stock_locations as $location)
            {
                $updated_quantity = parse_decimals($this->input->post('quantity_' . $location['location_id']));
                $location_detail = array('item_id' => $item_id,
                                        'location_id' => $location['location_id'],
                                        'quantity' => $updated_quantity);
                $item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location['location_id']);
                if($item_quantity->quantity != $updated_quantity || $new_item)
                {
                    $success &= $this->Item_quantity->save($location_detail, $item_id, $location['location_id']);

                    $inv_data = array(
                        'trans_date' => date('Y-m-d H:i:s'),
                        'trans_items' => $item_id,
                        'trans_user' => $employee_id,
                        'trans_location' => $location['location_id'],
                        'trans_comment' => $this->lang->line('items_manually_editing_of_quantity'),
                        'trans_inventory' => $updated_quantity - $item_quantity->quantity
                    );

                    $success &= $this->Inventory->insert($inv_data);
                }
            }

            if($success && $upload_success)
            {
                $message = $this->xss_clean($this->lang->line('items_successful_' . ($new_item ? 'adding' : 'updating')) . ' ' . $item_data['name']);

                echo json_encode(array('success' => TRUE, 'message' => $message, 'id' => $item_id));
            }
            else
            {
                $message = $this->xss_clean($upload_success ? $this->lang->line('items_error_adding_updating') . ' ' . $item_data['name'] : strip_tags($this->upload->display_errors()));

                echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => $item_id));
            }
        }
        else//failure
        {
            $message = $this->xss_clean($this->lang->line('items_error_adding_updating') . ' ' . $item_data['name']);
            
            echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => -1));
        }
    }
    
    public function check_item_number()
    {
        $exists = $this->Item->item_number_exists($this->input->post('item_number'), $this->input->post('item_id'));
        echo !$exists ? 'true' : 'false';
    }

    /*
    If adding a new item check to see if an item kit with the same name as the item already exists.
    */
    public function check_kit_exists()
    {
        if ($this->input->post('item_number') === -1)
        {
            $exists = $this->Item_kit->item_kit_exists_for_name($this->input->post('name'));
        }
        else
        {
            $exists = FALSE;
        }
        echo !$exists ? 'true' : 'false';
    }

    private function _handle_image_upload()
    {
        /* Let files be uploaded with their original name */
        
        // load upload library
        $config = array('upload_path' => './uploads/item_pics/',
            'allowed_types' => 'gif|jpg|png',
            'max_size' => '100',
            'max_width' => '640',
            'max_height' => '480'
        );
        $this->load->library('upload', $config);
        $this->upload->do_upload('item_image');
        
        return strlen($this->upload->display_errors()) == 0 || !strcmp($this->upload->display_errors(), '<p>'.$this->lang->line('upload_no_file_selected').'</p>');
    }

    public function remove_logo($item_id)
    {
        $item_data = array('pic_filename' => NULL);
        $result = $this->Item->save($item_data, $item_id);

        echo json_encode(array('success' => $result));
    }

    public function save_inventory($item_id = -1)
    {   
        $employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
        $cur_item_info = $this->Item->get_info($item_id);
        $location_id = $this->input->post('stock_location');
        $inv_data = array(
            'trans_date' => date('Y-m-d H:i:s'),
            'trans_items' => $item_id,
            'trans_user' => $employee_id,
            'trans_location' => $location_id,
            'trans_comment' => $this->input->post('trans_comment'),
            'trans_inventory' => parse_decimals($this->input->post('newquantity'))
        );
        
        $this->Inventory->insert($inv_data);
        
        //Update stock quantity
        $item_quantity = $this->Item_quantity->get_item_quantity($item_id, $location_id);
        $item_quantity_data = array(
            'item_id' => $item_id,
            'location_id' => $location_id,
            'quantity' => $item_quantity->quantity + parse_decimals($this->input->post('newquantity'))
        );

        if($this->Item_quantity->save($item_quantity_data, $item_id, $location_id))
        {
            $message = $this->xss_clean($this->lang->line('items_successful_updating') . ' ' . $cur_item_info->name);
            
            echo json_encode(array('success' => TRUE, 'message' => $message, 'id' => $item_id));
        }
        else//failure
        {
            $message = $this->xss_clean($this->lang->line('items_error_adding_updating') . ' ' . $cur_item_info->name);
            
            echo json_encode(array('success' => FALSE, 'message' => $message, 'id' => -1));
        }
    }

    public function bulk_update()
    {
        $items_to_update = $this->input->post('item_ids');
        $item_data = array();

        foreach($_POST as $key => $value)
        {       
            //This field is nullable, so treat it differently
            if($key == 'supplier_id' && $value != '')
            {   
                $item_data["$key"] = $value;
            }
            elseif($value != '' && !(in_array($key, array('item_ids', 'tax_names', 'tax_percents'))))
            {
                $item_data["$key"] = $value;
            }
        }

        //Item data could be empty if tax information is being updated
        if(empty($item_data) || $this->Item->update_multiple($item_data, $items_to_update))
        {
            $items_taxes_data = array();
            $tax_names = $this->input->post('tax_names');
            $tax_percents = $this->input->post('tax_percents');
            $tax_updated = FALSE;
            $count = count($tax_percents);
            for ($k = 0; $k < $count; ++$k)
            {       
                if(!empty($tax_names[$k]) && is_numeric($tax_percents[$k]))
                {
                    $tax_updated = TRUE;
                    
                    $items_taxes_data[] = array('name' => $tax_names[$k], 'percent' => $tax_percents[$k]);
                }
            }
            
            if($tax_updated)
            {
                $this->Item_taxes->save_multiple($items_taxes_data, $items_to_update);
            }

            echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('items_successful_bulk_edit'), 'id' => $this->xss_clean($items_to_update)));
        }
        else
        {
            echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_error_updating_multiple')));
        }
    }

    public function delete()
    {
        $items_to_delete = $this->input->post('ids');

        if($this->Item->delete_list($items_to_delete))
        {
            $message = $this->lang->line('items_successful_deleted') . ' ' . count($items_to_delete) . ' ' . $this->lang->line('items_one_or_multiple');
            echo json_encode(array('success' => TRUE, 'message' => $message));
        }
        else
        {
            echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_cannot_be_deleted')));
        }
    }

    /*
    Items import from excel spreadsheet
    */
    public function excel()
    {
        $name = 'import_items.csv';
        $data = file_get_contents('../' . $name);
        force_download($name, $data);
    }
    
    public function excel_import()
    {
        $this->load->view('items/form_excel_import', NULL);
    }

    public function do_excel_import()
    {
        if($_FILES['file_path']['error'] != UPLOAD_ERR_OK)
        {
            echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_failed')));
        }
        else
        {
            if(($handle = fopen($_FILES['file_path']['tmp_name'], 'r')) !== FALSE)
            {
                // Skip the first row as it's the table description
                fgetcsv($handle);
                $i = 1;
                
                $failCodes = array();
        
                while(($data = fgetcsv($handle)) !== FALSE)
                {
                    // XSS file data sanity check
                    $data = $this->xss_clean($data);
                    
                    /* haven't touched this so old templates will work, or so I guess... */
                    if(sizeof($data) >= 23)
                    {
                        $item_data = array(
                            'name'                  => $data[1],
                            'description'           => $data[11],
                            'category'              => $data[2],
                            'cost_price'            => $data[4],
                            'unit_price'            => $data[5],
                            'reorder_level'         => $data[10],
                            'supplier_id'           => $this->Supplier->exists($data[3]) ? $data[3] : NULL,
                            'allow_alt_description' => $data[12] != '' ? '1' : '0',
                            'is_serialized'         => $data[13] != '' ? '1' : '0',
                            'custom1'               => $data[14],
                            'custom2'               => $data[15],
                            'custom3'               => $data[16],
                            'custom4'               => $data[17],
                            'custom5'               => $data[18],
                            'custom6'               => $data[19],
                            'custom7'               => $data[20],
                            'custom8'               => $data[21],
                            'custom9'               => $data[22],
                            'custom10'              => $data[23]
                        );

                        /* we could do something like this, however, the effectiveness of
                          this is rather limited, since for now, you have to upload files manually
                          into that directory, so you really can do whatever you want, this probably
                          needs further discussion  */

                        $pic_file = $data[24];
                        /*if(strcmp('.htaccess', $pic_file)==0) {
                            $pic_file='';
                        }*/
                        $item_data['pic_filename'] = $pic_file;

                        $item_number = $data[0];
                        $invalidated = FALSE;
                        if($item_number != '')
                        {
                            $item_data['item_number'] = $item_number;
                            $invalidated = $this->Item->item_number_exists($item_number);
                        }
                    }
                    else 
                    {
                        $invalidated = TRUE;
                    }

                    if(!$invalidated && $this->Item->save($item_data))
                    {
                        $items_taxes_data = NULL;
                        //tax 1
                        if(is_numeric($data[7]) && $data[6] != '')
                        {
                            $items_taxes_data[] = array('name' => $data[6], 'percent' => $data[7] );
                        }

                        //tax 2
                        if(is_numeric($data[9]) && $data[8] != '')
                        {
                            $items_taxes_data[] = array('name' => $data[8], 'percent' => $data[9] );
                        }

                        // save tax values
                        if(count($items_taxes_data) > 0)
                        {
                            $this->Item_taxes->save($items_taxes_data, $item_data['item_id']);
                        }

                        // quantities & inventory Info
                        $employee_id = $this->Employee->get_logged_in_employee_info()->person_id;
                        $emp_info = $this->Employee->get_info($employee_id);
                        $comment ='Qty CSV Imported';

                        $cols = count($data);

                        // array to store information if location got a quantity
                        $allowed_locations = $this->Stock_location->get_allowed_locations();
                        for ($col = 25; $col < $cols; $col = $col + 2)
                        {
                            $location_id = $data[$col];
                            if(array_key_exists($location_id, $allowed_locations))
                            {
                                $item_quantity_data = array(
                                    'item_id' => $item_data['item_id'],
                                    'location_id' => $location_id,
                                    'quantity' => $data[$col + 1],
                                );
                                $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $location_id);

                                $excel_data = array(
                                    'trans_items' => $item_data['item_id'],
                                    'trans_user' => $employee_id,
                                    'trans_comment' => $comment,
                                    'trans_location' => $data[$col],
                                    'trans_inventory' => $data[$col + 1]
                                );
                                
                                $this->Inventory->insert($excel_data);
                                unset($allowed_locations[$location_id]);
                            }
                        }

                        /*
                         * now iterate through the array and check for which location_id no entry into item_quantities was made yet
                         * those get an entry with quantity as 0.
                         * unfortunately a bit duplicate code from above...
                         */
                        foreach($allowed_locations as $location_id => $location_name)
                        {
                            $item_quantity_data = array(
                                'item_id' => $item_data['item_id'],
                                'location_id' => $location_id,
                                'quantity' => 0,
                            );
                            $this->Item_quantity->save($item_quantity_data, $item_data['item_id'], $data[$col]);

                            $excel_data = array(
                                'trans_items' => $item_data['item_id'],
                                'trans_user' => $employee_id,
                                'trans_comment' => $comment,
                                'trans_location' => $location_id,
                                'trans_inventory' => 0
                            );

                            $this->Inventory->insert($excel_data);
                        }
                    }
                    else //insert or update item failure
                    {
                        $failCodes[] = $i;
                    }

                    ++$i;
                }

                if(count($failCodes) > 0)
                {
                    $message = $this->lang->line('items_excel_import_partially_failed') . ' (' . count($failCodes) . '): ' . implode(', ', $failCodes);
                    
                    echo json_encode(array('success' => FALSE, 'message' => $message));
                }
                else
                {
                    echo json_encode(array('success' => TRUE, 'message' => $this->lang->line('items_excel_import_success')));
                }
            }
            else 
            {
                echo json_encode(array('success' => FALSE, 'message' => $this->lang->line('items_excel_import_nodata_wrongformat')));
            }
        }
    }

    /**
     * Guess whether file extension is not in the table field,
     * if it isn't, then it's an old-format (formerly pic_id) field,
     * so we guess the right filename and update the table
     * @param $item the item to update
     */
    private function _update_pic_filename($item)
    {
        $filename = pathinfo($item->pic_filename, PATHINFO_FILENAME);
        if($filename=='')
        {
            // if the field is empty there's nothing to check
            return;
        }
        
        $ext = pathinfo($item->pic_filename, PATHINFO_EXTENSION);
        if ($ext == '') {
            $images = glob('./uploads/item_pics/' . $item->pic_filename . '.*');
            if (sizeof($images) > 0) {
                $new_pic_filename = pathinfo($images[0], PATHINFO_BASENAME);
                $item_data = array('pic_filename' => $new_pic_filename);
                $this->Item->save($item_data, $item->item_id);
            }
        }
    }
}
?>
API documentation generated by ApiGen