<?php


/**
 * Плъгин за документи към, които може да се разпределят разходи
 *
 *
 * @category  bgerp
 * @package   acc
 *
 * @author    Ivelin Dimov <ivelin_pdimov@abv.com>
 * @copyright 2006 - 2016 Experta OOD
 * @license   GPL 3
 *
 * @since     v 0.1
 */
class acc_plg_ExpenseAllocation extends core_Plugin
{
    /**
     * Извиква се след описанието на модела
     *
     * @param core_Mvc $mvc
     */
    public static function on_AfterDescription($mvc)
    {
        // Дефолтни имена на полетата от модела
        setIfNot($mvc->packQuantityFld, 'packQuantity');
        setIfNot($mvc->packagingFld, 'packagingId');
        setIfNot($mvc->quantityInPackFld, 'quantityInPack');
        setIfNot($mvc->productFld, 'productId');
        setIfNot($mvc->quantityFld, 'quantity');
        setIfNot($mvc->expenseItemAfterField, 'notes');
    }
    
    
    /**
     * Преди показване на форма за добавяне/промяна.
     *
     * @param core_Manager $mvc
     * @param stdClass     $data
     */
    public static function on_AfterPrepareEditForm($mvc, &$data)
    {
        $form = &$data->form;
        $rec = $form->rec;
        if (isset($rec->id)) {
            
            return;
        }
        
        // Ако началото на нишката не е Покупка или ФС, не се прави нищо
        $firstDocument = doc_Threads::getFirstDocument($data->masterRec->threadId);
        if (!$firstDocument->isInstanceOf('purchase_Purchases') && !$firstDocument->isInstanceOf('findeals_Deals')) {
            
            return;
        }
        
        // Добавяне на виртуални полета
        $form->FNC('expenseItemId', 'acc_type_Item(select=titleNum,allowEmpty,lists=600,showAll)', "input=none,after={$mvc->expenseItemAfterField},caption=Отнасяне (и разпределяне) на разходи->Разход за,removeAndRefreshForm=allocationBy");
        $form->FNC('allocationBy', 'enum(auto=Автоматично (по стойност),no=Няма,value=По стойност,quantity=По количество,weight=По тегло,volume=По обем)', 'input=none,caption=Отнасяне (и разпределяне) на разходи->Разпределяне,after=expenseItemId,silent,removeAndRefreshForm=chosenProducts|allocationFilter');
        $form->FNC('allocationFilter', 'enum(all=Всички артикули,storable=Само складируеми)', 'input=none,caption=Отнасяне (и разпределяне) на разходи->Артикули');

        // Ако е избран артикул
        if (isset($rec->productId)) {
            $pRec = cat_Products::fetch($rec->productId, 'canConvert,fixedAsset,canStore');
            
            // И той не е ДМА, не е Вложим и не е Складируем
            if ($pRec->canStore == 'no' && $pRec->fixedAsset == 'no' && $pRec->canConvert == 'no') {
                
                // И има поне две разходни пера
                if (acc_Lists::getItemsCountInList('costObjects') > 1) {
                    
                    // Показва се полето за избор на разход
                    $form->setField('expenseItemId', 'input');
                    if ($exItemId = Request::get('expenseItemId', 'int')) {
                        $form->setDefault('expenseItemId', $exItemId);
                    }
                    
                    // Ако е избран разход
                    if (isset($rec->expenseItemId)) {
                        
                        // и той е покупка или продажба, показва се полето за разпределяне
                        $itemClassId = acc_Items::fetchField($rec->expenseItemId, 'classId');
                        if (cls::haveInterface('acc_AllowArticlesCostCorrectionDocsIntf', $itemClassId)) {
                            $form->setField('allocationBy', 'input');
                            if ($allocationBy = Request::get('allocationBy', 'enum(auto,no,value,quantity,weight,volume)')) {
                                $form->setDefault('allocationBy', $allocationBy);
                            }
                            
                            if(in_array($itemClassId, array(sales_Sales::getClassId(), purchase_Purchases::getClassId()))){
                                $form->setDefault('allocationBy', 'auto');
                            } else {
                                $form->setDefault('allocationBy', 'no');
                            }

                            if($rec->allocationBy == 'auto'){
                                $form->setField('allocationFilter', 'input');
                                $form->setDefault('allocationFilter', 'all');
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    /**
     * Извиква се след въвеждането на данните от Request във формата ($form->rec)
     *
     * @param core_Mvc  $mvc
     * @param core_Form $form
     */
    public static function on_AfterInputEditForm($mvc, &$form)
    {
        $rec = $form->rec;

        if (isset($rec->allocationBy) && !in_array($rec->allocationBy, array('no', 'auto'))) {
            $itemRec = acc_Items::fetch($rec->expenseItemId);
            $origin = new core_ObjectReference($itemRec->classId, $itemRec->objectId);
            acc_ValueCorrections::addProductsFromOriginToForm($form, $origin, $mvc->Master);
        }

        if ($form->isSubmitted()) {

            if (isset($rec->id)) {
                // Колко разпределено по-реда
                $allocated = acc_CostAllocations::getAllocatedInDocument($mvc->getClassId(), $rec->id);
                $inputQuantity = $rec->{$mvc->quantityInPackFld} * $rec->{$mvc->packQuantityFld};
                
                // Проверка дали не е въведено по-малко к-во от вече разпределеното
                if ($inputQuantity < $allocated) {
                    $allocatedVerbal = cls::get('type_Double', array('params' => array('smartRound' => true)))->toVerbal($allocated);
                    $uomName = cat_UoM::getShortName(key(cat_Products::getPacks($rec->productId)));
                    $form->setError($mvc->packQuantityFld, "Въведеното к-во е по-малко от к-то разпределеното по разходи|* <b>{$allocatedVerbal}</b> |{$uomName}|*");
                }
            } elseif(isset($rec->expenseItemId) && isset($rec->allocationBy)) {
                if(!in_array($rec->allocationBy, array('no', 'auto'))){
                    if (!countR($form->allProducts)) {
                        $form->setError('allocationBy,expenseItemId', 'В избраната сделка няма експедирани/заскладени артикули');
                    }
                }

                if($rec->allocationBy == 'auto'){
                    $itemRec = acc_Items::fetch($rec->expenseItemId, 'classId,objectId');
                    $origin = new core_ObjectReference($itemRec->classId, $itemRec->objectId);
                    $rec->productsData = $origin->getCorrectableProducts($mvc->Master, $rec->allocationFilter);
                } elseif(isset($rec->chosenProducts)){
                    $rec->productsData = array_intersect_key($form->allProducts, type_Set::toArray($rec->chosenProducts));
                }

                $expenseItemError = null;
                if(!acc_CostAllocations::checkSelectedExpenseItem($rec->expenseItemId, $rec->allocationFilter, $mvc, $rec->id, $expenseItemError)){
                    $form->setError('expenseItemId', $expenseItemError);
                }

                if(!$form->gotErrors()){
                    if($rec->allocationBy != 'no'){
                        $packQuantity = isset($rec->packQuantity) ? $rec->packQuantity : deals_Helper::getDefaultPackQuantity($rec->productId, $rec->packagingId);
                        if ($error = acc_ValueCorrections::allocateAmount($rec->productsData, $packQuantity, $rec->allocationBy)) {
                            $form->setError('allocateBy,chosenProducts', $error);
                        }
                    }
                }
            }
        }
    }
    
    
    /**
     * Изпълнява се след създаване на нов запис
     */
    public static function on_AfterCreate($mvc, $rec)
    {
        // След създаване, ако има избрано разходно перо
        if (isset($rec->expenseItemId)) {
            $containerId = $mvc->Master->fetchField($rec->{$mvc->masterKey}, 'containerId');
            
            // Записва се в регистъра на разходи
            $costRec = (object) array('detailClassId' => $mvc->getClassId(),
                'expenseItemId' => $rec->expenseItemId,
                'allocationBy' => $rec->allocationBy,
                'detailRecId' => $rec->id,
                'productId' => $rec->{$mvc->productFld},
                'quantity' => $rec->{$mvc->quantityFld},
                'allocationFilter' => $rec->allocationFilter,
                'productsData' => $rec->productsData,
                'containerId' => $containerId);
            
            // Запис на разхода
            acc_CostAllocations::save($costRec);
        }
    }
    
    
    /**
     * Колко е максималното к-во за реда
     */
    public static function on_AfterGetMaxQuantity($mvc, &$res, $id)
    {
        if (!$res) {
            $res = $mvc->fetchField($id, $mvc->quantityFld);
        }
    }
    
    
    /**
     * След изтриване на запис
     */
    public static function on_AfterDelete($mvc, &$numDelRows, $query, $cond)
    {
        // След изтриване на ред, се изтриват съответстващите му записи
        foreach ($query->getDeletedRecs() as $id => $rec) {
            acc_CostAllocations::delete("#detailClassId = {$mvc->getClassId()} AND #detailRecId = {$id}");
        }
    }
    
    
    /**
     * Преди рендиране на таблицата
     */
    protected static function on_BeforeRenderListTable($mvc, &$tpl, $data)
    {
        $rows = &$data->rows;
        if (!countR($rows)) {
            
            return;
        }
        
        foreach ($rows as $id => $row) {
            $rec = $data->recs[$id];
            
            // Показване на разпределените разходи за всеки ред
            $row->productId .= acc_CostAllocations::getAllocatedExpenses($mvc, $rec->id, $data->masterData->rec->containerId, $rec->{$mvc->productFld}, $rec->{$mvc->packagingFld}, $rec->{$mvc->quantityInPackFld});
        }
    }
}
