<?php 

/**
 * Мениджира детайлите на стелажите (rack_RackDetails)
 *
 *
 * @category  bgerp
 * @package   rack
 *
 * @author    Ivelin Dimov <ivelin_pdimov@abv.bg>
 * @copyright 2006 - 2025 Experta OOD
 * @license   GPL 3
 *
 * @since     v 0.1
 */
class rack_RackDetails extends core_Detail
{
    /**
     * Заглавие
     */
    public $title = 'Детайли на стелаж';
    
    
    /**
     * Заглавие в единствено число
     */
    public $singleTitle = 'Състояние на клетка';
    
    
    /**
     * Плъгини за зареждане
     */
    public $loadList = 'plg_RowTools2, rack_Wrapper';
    
    
    /**
     * Име на поле от модела, външен ключ към мастър записа
     */
    public $masterKey = 'rackId';
    
    
    /**
     * Кой има право да променя?
     */
    public $canEdit = 'ceo, rack';
    
    
    /**
     * Кой има право да добавя?
     */
    public $canAdd = 'ceo, rackMaster';
    
    
    /**
     * Кой може да го изтрие?
     */
    public $canDelete = 'ceo, rackMaster';
    
    
    /**
     * Полета за листовия изглед
     */
    public $listFields = 'rackId,position=Позиция,status,productId';


    /**
     * Кой може да го разглежда?
     */
    public $canList = 'ceo,rackSee';


    /**
     * Описание на модела
     */
    public function description()
    {
        $this->FLD('rackId', 'key(mvc=rack_Racks)', 'caption=Стелаж, input=hidden,silent');
        $this->FLD('row', 'varchar(1)', 'caption=Ред,smartCenter,silent');
        $this->FLD('col', 'int', 'caption=Колона,smartCenter,silent');
        $this->FLD('status', 'enum(usable=Използваемо,
                                   unusable=Неизползваемо,
                                   reserved=Запазено (твърдо), 
                                   reservedSoft=Запазено (препоръчително)                                   
                                   )', 'caption=Състояние,smartCenter,silent,refreshForm');
        $this->FLD('productId', 'key2(mvc=cat_Products, select=name,allowEmpty,selectSourceArr=cat_Products::getProductOptions,allowEmpty,hasProperties=canStore,hasnotProperties=generic)', 'caption=Артикул,input=none');
        
        $this->setDbUnique('rackId,row,col');
    }
    
    
    /**
     * Преди показване на форма за добавяне/промяна.
     *
     * @param core_Manager $mvc
     * @param stdClass     $data
     */
    public static function on_AfterPrepareEditForm($mvc, &$data)
    {
        $form = $data->form;
        $rec = &$form->rec;
        
        $form->FLD('nextRow', 'varchar(1,select2MinItems=1000)', 'caption=Повторение на състоянието до:->Ред,smartCenter,autohide,class=w25');
        $form->FLD('nextCol', 'int(select2MinItems=1000)', 'caption=Повторение на състоянието до:->Колона,smartCenter,autohide,class=w25');
        
        expect($rec->rackId);
        $rRec = rack_Racks::fetch($rec->rackId);
        expect($rRec);
        store_Stores::selectCurrent(store_Stores::fetch($rRec->storeId));
        
        $r = 'A';
        $o = array('' => '');
        do {
            $o[$r] = $r;
            $r = chr(ord($r) + 1);
        } while ($r <= $rRec->rows);
        $form->setOptions('row', $o);
        $form->setOptions('nextRow', $o);
        
        $c = 1;
        $o2 = array('' => '');
        do {
            $o2[$c] = $c;
            $c++;
        } while ($c <= $rRec->columns);
        $form->setOptions('col', $o2);
        $form->setOptions('nextCol', $o2);
        
        expect($rec->rackId && $rec->row && $rec->col, $rec);
        $form->setReadOnly('row');
        $form->setReadOnly('col');
        
        if (!$rec->id) {
            if ($exRec = self::fetch(array("#rackId = [#1#] AND #row = '[#2#]' AND #col = [#3#]", $rec->rackId, $rec->row, $rec->col))) {
                $rec = $exRec;
            }
        }

        if (in_array($rec->status, array('reservedSoft', 'reserved'))) {
            $form->setField('productId', 'input=input');
        }
        
        // Ако има палет на това място, или към него е насочено движение
        // То статусът може да е само 'Използваемо'
        if (!rack_Pallets::isEmpty(null, "{$data->masterRec->num}-{$rec->row}-{$rec->col}", null)) {
            setIfNot($rec->status, 'usable');
            $form->setReadOnly('status');
        }
    }
    
    
    /**
     * Извиква се след въвеждането на данните от Request във формата ($form->rec)
     *
     * @param core_Mvc  $mvc
     * @param core_Form $form
     */
    public static function on_AfterInputEditForm($mvc, &$form)
    {
        if ($form->isSubmitted()) {
            $rec = $form->rec;
            
            if ($rec->nextRow || $rec->nextCol) {
                if (empty($rec->nextRow)) {
                    $rec->nextRow = $rec->row;
                }
                if (empty($rec->nextCol)) {
                    $rec->nextCol = $rec->col;
                }
                
                // Вземаме параметрите на стелажа
                $rRec = rack_Racks::fetch($rec->rackId);
                
                $maxX = $rRec->columns;
                $maxY = ord($rRec->rows);
                
                $x1 = $rec->col;
                $y1 = ord($rec->row);
                
                $x2 = $rec->nextCol;
                $y2 = ord($rec->nextRow);
                
                list($unusable, $reserved, $reservedSoft) = rack_RackDetails::getUnusableAndReserved();
                $reserved += $reservedSoft;

                $used = rack_Pallets::getUsed($rec->productId);
                list($movedFrom, $movedTo) = rack_Movements::getExpected();
                
                for ($x = 1; $x <= $maxX; $x++) {
                    for ($y = ord('A'); $y <= $maxY; $y++) {
                        $pos = $rRec->num . '-' . chr($y) . '-' . $x;
                        
                        
                        // Ако текущата позиция е в очертанията, добавяме я в масива
                        if (($x1 - $x) * ($x2 - $x) <= 0 && ($y1 - $y) * ($y2 - $y) <= 0) {
                            if ($movedFrom[$pos] || $movedTo[$pos]) {
                                $form->setError('nextCol,nextRow', 'Има текущи движения, които засягат посочената област' . "|* [{$pos}]");
                            }
                            
                            if ($rec->status == 'unusable') {
                                if ($used[$pos]) {
                                    $form->setError('nextCol,nextRow', 'В посочената област има заети позиции' . "|* [{$pos}]");
                                }
                                if ($reserved[$pos]) {
                                    $form->setError('nextCol,nextRow', 'В посочената област има резервирани позиции' . "|* [{$pos}]");
                                }
                            }
                            
                            if ($used[$pos]) {
                                if ($rec->status == 'reserved' && $used[$pos]->productId != $rec->productId) {
                                    $form->setError('nextCol,nextRow', 'В посочената област има други артикули' . "|* [{$pos}]");
                                }
                                if ($rec->status != 'reserved') {
                                    $form->setError('nextCol,nextRow', 'В посочената област има заети позиции' . "|* [{$pos}]");
                                }
                            }
                            
                            if ($unusable[$pos] && $rec->status != 'usable') {
                                continue;
                            }
                            
                            $add = clone $rec;
                            unset($add->id, $add->_toSave);
                            $add->col = $x;
                            $add->row = chr($y);
                            $rec->_toSave[] = $add;
                        }
                    }
                }
            }
        }
    }
    
    
    /**
     * Извиква се след успешен запис в модела
     *
     * @param core_Mvc $mvc
     * @param int      $id  първичния ключ на направения запис
     * @param stdClass $rec всички полета, които току-що са били записани
     */
    public static function on_AfterSave(core_Mvc $mvc, &$id, $rec)
    {
        if (is_array($rec->_toSave) && countR($rec->_toSave)) {
            foreach ($rec->_toSave as $r) {
                $r->id = self::fetch("#col = {$r->col} AND #row = '{$r->row}' AND #rackId = {$r->rackId}")->id;
                
                self::save($r);
            }
        }
    }
    
    
    /**
     * Връща масив с масиви, отговарящи на запазените и неизползваемите места в склада
     */
    public static function getUnusableAndReserved($storeId = null)
    {
        if (!$storeId) {
            $storeId = store_Stores::getCurrent();
        }
        
        if (true || !($res = core_Cache::get('getUnusableAndReserved', $storeId))) {
            $res = array(0 => array(), 1 => array(), 2 => array());
            $rQuery = rack_Racks::getQuery();
            while ($rRec = $rQuery->fetch("#storeId = {$storeId}")) {
                $query = self::getQuery();
                while ($rec = $query->fetch("#rackId = {$rRec->id}")) {
                    $pos = "{$rRec->num}-{$rec->row}-{$rec->col}";
                    if ($rec->status == 'reservedSoft') {
                        $res[2][$pos] = $rec->productId ? $rec->productId : -1;
                    } elseif ($rec->status == 'reserved') {
                        $res[1][$pos] = $rec->productId ? $rec->productId : -1;
                    } elseif ($rec->status == 'unusable') {
                        $res[0][$pos] = true;
                    }
                }
            }

            core_Cache::set('getUnusableAndReserved', $storeId, $res, 1440);
        }

        return $res;
    }


    /**
     * След преобразуване на записа в четим за хора вид.
     *
     * @param core_Mvc $mvc
     * @param stdClass $row Това ще се покаже
     * @param stdClass $rec Това е записа в машинно представяне
     */
    protected static function on_AfterRecToVerbal($mvc, &$row, $rec, $fields = array())
    {
        if(isset($rec->productId)){
            $row->productId = cat_Products::getHyperlink($rec->productId, true);
        }

        $rackRec = rack_Racks::fetch($rec->rackId);
        $row->rackId = rack_Racks::getHyperlink($rec->rackId, true);
        $row->position = core_Type::getByName('rack_PositionType')->toVerbal("{$rackRec->num}-{$rec->row}-{$rec->col}");
    }


    /**
     * Добавя филтър към перата
     *
     * @param acc_Items $mvc
     * @param stdClass  $data
     */
    protected static function on_AfterPrepareListFilter($mvc, $data)
    {
        $storeId = store_Stores::getCurrent();
        $data->query->EXT('storeId', 'rack_Racks', 'externalName=storeId,externalKey=rackId');
        $data->query->where("#storeId = {$storeId}");
        $data->title = 'Детайли на стелажи в склад |*<b style="color:green">' . store_Stores::getHyperlink($storeId, true) . '</b>';
        $data->query->orderBy('#rackId', 'ASC');
    }
}
