Skip to content
Snippets Groups Projects
Select Git revision
  • ae0c55a441ed950e90fb2c4c33b69e7032a66274
  • main default
2 results

controller.go

Blame
  • controller.go 4.97 KiB
    /**
     * controller.go
     *
     * COPYRIGHT: FUNDACIÓN TECNALIA RESEARCH & INNOVATION, 2022.
     */
    
    package discard
    
    import (
    	"errors"
    
    	"git.code.tecnalia.com/ledgerbuilder/sdk/core/api"
    	"git.code.tecnalia.com/ledgerbuilder/sdk/core/controller"
    	"git.code.tecnalia.com/ledgerbuilder/sdk/core/fabric/protos"
    	"git.code.tecnalia.com/ledgerbuilder/sdk/shared"
    
    	"git.code.tecnalia.com/blockchain/hypercog/controller/stats"
    
    	errs "git.code.tecnalia.com/traceblock/sdk/constants"
    	"git.code.tecnalia.com/traceblock/sdk/controller/base"
    	"git.code.tecnalia.com/traceblock/sdk/controller/split"
    	"git.code.tecnalia.com/traceblock/sdk/model"
    )
    
    type DiscardController struct {
    	base.TraceblockBaseController
    }
    
    var (
    	errInvalidInputData     = errors.New("failed to read model")
    	errInvalidDiscardQuantity = errors.New("quantity to discard is greater than the available quantity")
    )
    
    // constructor like function
    func NewDiscardController() *DiscardController {
    	ctl := new(DiscardController)
    	ctl.LowLevelController = controller.NewLowLevelController()
    	ctl.SetDataModelClosure(ctl.modelClosure)
    	return ctl
    }
    
    func (c DiscardController) modelClosure(stub shared.LedgerBuildrStubInterface) shared.LedgerBuildrAsset {
    	return NewDiscardParams()
    }
    
    func (c DiscardController) readTraceableAsset(stub shared.LedgerBuildrStubInterface, assetId string) (*model.TraceableAsset, error) {
    	readedModel, err := c.ReadAbstractAssetAndReturn(stub, assetId, model.NewTraceableAsset())
    	if err != nil {
    		return nil, err
    	}
    
    	// asset data successfully readed
    	asset, ok := readedModel.(*model.TraceableAsset)
    	if !ok {
    		return nil, errs.NotExistingAsset
    	}
    
    	return asset, nil
    }
    
    func (c DiscardController) readAsset(stub shared.LedgerBuildrStubInterface, requestAsset shared.LedgerBuildrAsset) (*model.TraceableAsset, error) {
    	return c.readTraceableAsset(stub, requestAsset.GetID())
    }
    
    
    // HyperCOG specific discard operation
    func  (c DiscardController) _discardAsset(stub shared.LedgerBuildrStubInterface, params *DiscardParams, discardableAsset *model.TraceableAsset) (*protos.Response, error) {
    	if discardableAsset.Quantity < params.Quantity {
    		return nil, errInvalidDiscardQuantity
    	}
    
    	var discardedStock *model.TraceableAsset
    	generatedIds := make([]string, 2)
    
    	if params.Quantity == discardableAsset.Quantity {
    		discardedStock = discardableAsset
    	} else {
    		// discardableAsset.Quantity > discardParams.Quantity
    		splitParams := new(split.SplitParams)
    		splitParams.SetID(discardableAsset.GetID())
    		splitParams.SplitConfig.ArchiveOld = true
    		splitParams.SplitConfig.Bidirectional = true
    		splitParams.SplitConfig.ChildCount = 2
    		splitParams.SplitConfig.BaseAsset.AssetType = discardableAsset.AssetType
    		splitParams.SplitConfig.BaseAsset.ArbitraryDataFields = discardableAsset.ArbitraryDataFields
    
    		subAssets, err := split.SplitAsset(c.TraceblockBaseController, stub, discardableAsset, *splitParams)
    		if err != nil {
    			return nil, err
    		}
    
    		for i, c := range subAssets {
    			generatedIds[i] = c.GetID()
    		}
    
    		newStock := subAssets[0]
    		newStock.Quantity = discardableAsset.Quantity - params.Quantity
    		newStock.Units = discardableAsset.Units
    
    		respNewStock:= c.SaveAbstractAsset(stub, &newStock)
    		if respNewStock.Status != shared.OK {
    			return &respNewStock, nil
    		}
    
    		discardedStock = &subAssets[1]
    		discardedStock.Quantity = params.Quantity
    		discardedStock.Units = discardableAsset.Units
    		discardedStock.Add("name", " Discarded")
    	}
    
    	err := stats.RegisterDiscard(stub, discardedStock.Quantity, discardedStock.Units)
    	if err != nil {
    		return nil, err
    	}
    
    
    	discardedStock.Add("status", "discarded")
    	// Already marked as modified
    	discardedStock.MarkAsDeleted()
    	respDiscarted := c.SaveAbstractAsset(stub, discardedStock)
    	if respDiscarted.Status != shared.OK {
    		return &respDiscarted, nil
    	}
    
    	ret := api.NewAPIGenericResponsePtr("DiscardController:Discard", nil, generatedIds).SendResponse()
    	return &ret, nil
    }
    
    func  (c DiscardController) _archiveAsset(stub shared.LedgerBuildrStubInterface, params shared.LedgerBuildrAsset) (*protos.Response, error) {
    	discardParams, ok := params.(*DiscardParams)
    	if discardParams == nil || !ok {
    		//failed when casting/fetching input data
    		return nil, errInvalidInputData
    	}
    
    	discardableAsset, err := c.readAsset(stub, discardParams)
    	if err != nil {
    		return nil, err
    	}
    
    	status, ok := discardableAsset.Get("status")
    	if status != "stocked" || status == "stocked" && discardParams.Quantity == 0 {
    		// Done in MarkAssetAsDeleted middleware in normal operation
    		discardableAsset.MarkModification(stub)
    		discardableAsset.MarkAsDeleted()
    
    		responseArchive := c.DeleteAbstractAsset(stub, discardableAsset)
    		return &responseArchive, nil
    	}
    
    	// HyperCOG specific discard operation
    	return c._discardAsset(stub, discardParams, discardableAsset)
    }
    
    func (c DiscardController) Discard(stub shared.LedgerBuildrStubInterface, params shared.LedgerBuildrAsset) protos.Response {
    	ret, err := c._archiveAsset(stub, params)
    	if err != nil {
    		return api.NewApiResponsePtr("DiscardController:Discard", err, nil).SendResponse()
    	}
    	return *ret
    }